Java提供的线程池出自并发大师Doug Lea之手,向大师致敬!
1. 为什么要用线程池
合理使用线程池可以带来3个好处:
- 降低资源消耗。重复利用已经创建的线程,避免线程重复创建带来的消耗。
- 提高响应速度。当任务到达时,任务不必等线程创建即可立即执行。
-
提高线程的可管理性。使用线程池可以对线程统一分配、调优和监控。
总之,线程池是为了资源复用、提高效率、方便管理的产物。“池”的作用有两点:一是复用已有资源,二是控制资源总量
2. 线程池的原理
当向线程池提交了一个任务之后,线程池是如何处理这个任务的呢?
- 首先线程池判断核心线程池的线程是否都在执行任务,如果不是泽创建一个线程执行任务,否则就如下一个流程。
- 线程池判断任务队列是否已经满了,如果没有满则将任务存储在工作队列里面,如果满了则进入下一个流程。
-
线程池判断线程是否都已经处于工作状态,如果没有则创建一个线程执行任务,如果已经满了则交给策略处理无法完成的任务。
线程池任务处理流程
ThreadPoolExecutor执行示意图
3. 线程池的使用
通过ThreadPoolExecutor来创建一个线程池:
new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, queue)
创建完成后通过ThreadPoolExecutor的execute(sumbmit最终也是调用execute执行任务)方法向线程池提交任务,代码如下:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
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);
}
else if (!addWorker(command, false))
reject(command);
}
- execute方法首先判断当前运行线程少于corePoolSize,则创建新线程任务来执行任务
- 如果运行线程等于或多于corePoolSize,则将任务加入到队列
- 如果无法将任务加入到队列,则创建新线程执行任务
- 创建新线程时如果数量超过maxPoolSize则拒绝执行任务,这里需要注意一下如果构造ThreadPoolExecutor传入的是无界队列,maxPoolSize无效,最大线程数将是corePoolSize
网友评论