JUC(二) | 线程池浅谈
前面简单学习了JUC同步辅助类,今天一起走进线程池的美妙新世界。
一、从新建线程池谈起
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
-
类的区别
Executor是执行者接口,通过execute方法执行Runnable任务;
ExecutorService是执行者服务接口,通过submit将任务提交给Executor执行;
ThreadPoolExecutor是真正的实现类;
Executors是静态工厂类,可以返回ExecutorService等; -
参数概念
corePoolSize : 线程池中允许同时运行的线程数;
maximumPoolSize : 线程池中允许创建的最大线程数;
keepAliveTime:线程池空闲后,超过此时间的线程会被终止;
workQueue :线程任务阻塞队列;
defaultThreadFactory : 返回线程工厂,线程池中的线程均是由线程工厂创建;
defaultHandler:任务添加到线程池中,线程池拒绝时采取的策略;
二、以execute方法为重
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//策略一:线程池中运行数量小于corePoolSize时,直接新建任务
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//策略二:线程池中大于等于corePoolSize时,且线程池状态允许时,将任务添加到阻塞队列中
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//策略三:线程池中大于等于corePoolSize时,且线程池状态不允许时,直接新建任务
else if (!addWorker(command, false))
reject(command);
}
- addWork源码解读
- 上面代码中多次谈到线程池状态及拒绝策略,下一步深入理解
三、线程池状态及转换
- 与线程的五种状态不同,线程池的五种状态及其转换如下图所示:
Running:能接受新任务,且处理已添加任务;(对应于isRunning检测)
ShutDown:不能接受新任务,可处理已添加任务;
Stop:不能接受新任务,且会中断已处理任务;
Tidying:所有任务已经终止;
Terminated:Tidying状态后,执行钩子函数terminate,进入此状态;
四、拒绝策略
AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常;
CallerRunsPolicy:当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务;
DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中;
DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务;