共计 1171 个字符,预计需要花费 3 分钟才能阅读完成。
合理的使用线程池有三个好处:
1. 降低资源消耗。
2. 提高响应速度。
3. 提高线程的可管理性。
线程池的实现原理
先看流程图:
如果当前线程池中的线程数目小于 corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;如果当前线程池中的线程数 >=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若任务缓存队列已满,则会尝试创建新的线程去执行这个任务;如果当前线程池中的线程数目达到 maximumPoolSize,则会采取任务拒绝策略进行处理。
看一下 excute 的源码:
public void execute(Runnable command) {if (command == null) // 空任务抛出异常
throw new NullPointerException();
int c = ctl.get();
// 1. 如果工作线程数小于核心线程数,则添加新的线程
if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))
return; // 添加成功则返回
c = ctl.get(); // 否则获取线程池状态}
// 2. 工作线程数大于等于核心线程数,则将任务放入缓存任务队列
// 与操作:如果线程池正在运行,而且成功将任务插入缓存任务队列两个条件
// 都满足则进入条件语句内
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); // 添加无初始任务的线程
}
// 3. 任务入队失败,说明任务缓存任务队列已满,尝试添加新的线程处理
// 如果添加失败则以某种方式拒绝任务
else if (!addWorker(command, false))
reject(command);
}
线程池创建线程时,会将线程封装成工作线程 Worker,Worker 在执行完任务后,还会循环获取工作队列里的任务来执行。可以从 Worker 类的 run()方法里看出这点:
public void run(){
try{Runnable task = firstTask();
firstTask() = null;
while (task != null || (task = getTask()) != null){runTask(task);
task = null ;
}finally{workerDone(this);
}
}
}
正文完