
【JDK源码分析系列】ThreadPoolExecutor 源码解析 -- 线程池终止
发布日期:2021-05-07 20:51:25
浏览次数:20
分类:原创文章
本文共 4761 字,大约阅读时间需要 15 分钟。
【JDK源码分析系列】ThreadPoolExecutor 源码解析 -- 线程池终止
【1】线程池终止
【1.1】ThreadPoolExecutor -- shutdown
//shutdown() -- 温柔的终止线程池public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //判断调用者是否有权限shutdown线程池 checkShutdownAccess(); //CAS+循环设置线程池状态为shutdown advanceRunState(SHUTDOWN); //中断所有空闲线程 interruptIdleWorkers(); //shutdown 回调方法 //由子类实现 onShutdown(); // hook for ScheduledThreadPoolExecutor } finally { mainLock.unlock(); } //尝试终止线程池 tryTerminate();}
private void checkShutdownAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(shutdownPerm); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) security.checkAccess(w.thread); } finally { mainLock.unlock(); } }}private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; }}//回收空余线程//onlyOne如果为true,最多interrupt一个worker//只有当终止流程已经开始,但线程池还有worker线程时,tryTerminate()方法会做调用onlyOne为true的调用//(终止流程已经开始指的是:shutdown状态且workQueue为空或者stop状态)//在这种情况下,最多有一个worker被中断,为了传播shutdown信号,以免所有的线程都在等待//为保证线程池最终能终止,这个操作总是中断一个空闲worker//而shutdown()中断所有空闲worker,来保证空闲线程及时退出private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //循环回收,onlyOne=false,说明要回收很多个 for (Worker w : workers) { Thread t = w.thread; //线程没有被打断,并且worker可以获得锁,那么当前线程可以被打断 if (!t.isInterrupted() && w.tryLock()) { try { //建议线程中断 t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) //退出循环 break; } } finally { mainLock.unlock(); }}//试图终止//在以下情况将线程池变为TERMINATED终止状态//shutdown且正在运行的worker和workQueue队列都empty//stop且没有正在运行的worker////这个方法必须在任何可能导致线程池终止的情况下被调用,如://减少worker数量//shutdown时从queue中移除任务//这个方法不是私有的,所以允许子类ScheduledThreadPoolExecutor调用final void tryTerminate() { for (;;) { int c = ctl.get(); //正在运行 if (isRunning(c) || //tidying terminated runStateAtLeast(c, TIDYING) || //shutdown 且 队列不为空 (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) //综合上面3个条件,可以推断出当线程池stop或者shutdown //且任务队列为空,就可以去terminated了 return; //worker的数量不为零,说明还有任务在执行,所以先不要terminated线程池 if (workerCountOf(c) != 0) { // Eligible to terminate interruptIdleWorkers(ONLY_ONE); return; } //如果状态是SHUTDOWN,workQueue也为空了,正在运行的worker也没有了,开始terminated final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //CAS:将线程池的ctl变成TIDYING(所有的任务被终止,workCount为0,为此状态时将会调用terminated()方法), //期间ctl有变化就会失败,会再次for循环 if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { try { //终止线程, 由子类实现 terminated(); } finally { //将线程池的ctl变成TERMINATED ctl.set(ctlOf(TERMINATED, 0)); //唤醒调用等待线程池终止的线程awaitTermination() termination.signalAll(); } return; } } finally { mainLock.unlock(); } // else retry on failed CAS // 如果上面的CAS判断false,再次循环 }}
【1.2】ThreadPoolExecutor -- shutdownNow
//shutdownNow() -- 强硬的终止线程池public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //判断调用者是否有权限shutdown线程池 checkShutdownAccess(); //CAS+循环设置线程池状态为stop advanceRunState(STOP); //中断所有线程,包括正在运行任务的 interruptWorkers(); //将workQueue中的元素放入一个List并返回 tasks = drainQueue(); } finally { mainLock.unlock(); } //尝试终止线程池 tryTerminate(); return tasks;}
//变量所有的 worker 并中断这些 workerprivate void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); }}
【1.3】ThreadPoolExecutor -- awaitTermination
当前线程阻塞,直到
等所有已提交的任务(包括正在跑的和队列中等待的)执行完
或者等超时时间到
或者线程被中断,抛出InterruptedException
然后返回true(shutdown请求后所有任务执行完毕)或false(已超时)
参考致谢
本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。
【1】
【2】
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2025年04月08日 22时40分59秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
广度优先搜索
2021-05-07
Dijkstra算法的总结
2021-05-07
C语言的运算符和表达式
2021-05-07
Vue实现选项卡功能
2021-05-07
uni-app请求头中携带token
2021-05-07
vue中接收后台的图片验证码并显示
2021-05-07
Vue入门学习笔记(1)
2021-05-07
趣谈win10常用快捷键
2021-05-07
数学建模更新12(数学线性规划模型1)
2021-05-07
Android,SharedPreferences的使用
2021-05-07
两款用于检测内存泄漏的软件
2021-05-07
王爽 《汇编语言》 读书笔记 三 寄存器(内存访问)
2021-05-07
OSI 7 层网络模型
2021-05-08
JDK 内置的多线程协作工具类的使用场景
2021-05-08
Java 中哪些对象可以获取类对象
2021-05-08
linux 的 sleep 命令
2021-05-08