CachedThreadPool里的线程是如何被回收的?
线程池创建线程的逻辑图:

我们分析CachedThreadPool线程池里的线程是如何被回收的。
//Executors
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
} //ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
牢牢记住CachedThreadPool的corePoolSize=0, maximumPoolSize=Integer.MAX_VALUE
工作线程的死循环:
//ThreadPoolExecutor
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
当工作线程第二次获取的task等于null时,线程将退出while循环,于是就死掉了。
//ThreadPoolExecutor
private Runnable getTask() {
// 标记poll()是否超时
boolean timedOut = false; retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//工作线程数-1
decrementWorkerCount();
//返回null,工作线程将退出while循环,即线程会死掉
return null;
} boolean timed; // Are workers subject to culling? for (;;) {
int wc = workerCountOf(c);
// allowCoreThreadTimeOut 默认为 false, newCachedThreadPool的corePoolSize为0
// 所以 timed = false || true,timed恒为true
timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 对于newCachedThreadPool,wc 恒小于 maximumPoolSize
// 第一次进for循环 true && !(false && true) = true
// poll超时后,第二次进for循环 true && !(true && true) = false
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
if (compareAndDecrementWorkerCount(c))
//poll超时后,第二次进for循环,
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
} try {
//走poll分支
//poll会阻塞,直到有人调用workQueue.offer;或者超时返回null
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
//超时
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
如图中所示:有2种情况会创建工作线程,1. 工作线程数小于corePoolSize;2. 入队失败,且工作线程数小于maximumPoolSize
//ThreadPoolExecutor
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();
}
//对于CachedThreadPool,如果有工作线程在poll中阻塞,则入队成功
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);
}
//对于CachedThreadPool,如果没有工作线程在poll中阻塞,则入队失败
//初次调用execute,走这个分支,创建工作线程
else if (!addWorker(command, false))
reject(command);
}
CachedThreadPool使用的是SynchronousQueue的
入队 :offer(E e)
出队:poll(long timeout, TimeUnit unit)
工作线程调用poll阻塞,等待timeout时间,如果超时,则返回null并回收线程;如果在等待期内,有任务入队,则成功返回任务,继续执行线程while循环。
CachedThreadPool里的线程是如何被回收的?的更多相关文章
- Linux线程退出、资源回收、资源清理的方法
首先说明线程中要回收哪些资源,理解清楚了这点之后在思考资源回收的问题. 1.子线程创建时从父线程copy出来的栈内存; 线程退出有多种方式,如return,pthread_exit,pthread_c ...
- 小谈Java里的线程
今天,我们来谈一谈Java里的线程. 一.进程与线程的基本概念 大家可能没听过线程这个概念,但是相信,用计算机的朋友都听过进程这个概念.打开电脑的任务管理器,我们就可以看到许多进程.它们主要分为三类, ...
- Linux 系统编程 学习:09-线程:线程的创建、回收与取消
Linux 系统编程 学习:09-线程:线程的创建.回收与取消 背景 我们在此之前完成了 有关进程的学习.从这一讲开始我们学习线程. 完全的开发可以参考:<多线程编程指南> 在Linux ...
- 并发编程——认识java里的线程
本文系作者 chaoCode原创,转载请私信并在文章开头附带作者和原文地址链接. 违者,作者保留追究权利. 前言 并发编程在我们日常开发中是时时刻刻都有在用的,只不过大部分的代码底层已经帮我们去做了一 ...
- 简短总结一下C#里跨线程更新UI(转)
摘自: http://my.oschina.net/sdqxcxh/blog/53707 跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI ...
- 简短总结一下C#里跨线程更新UI
摘自: http://my.oschina.net/sdqxcxh/blog/53707 跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI ...
- 【原创】一个线程oom,进程里其他线程还能运行吗?
引言 这题是一个网友@大脸猫爱吃鱼给我的提问,出自今年校招美团三面的一个真题.大致如下 一个进程有3个线程,如果一个线程抛出oom,其他两个线程还能运行么? 先说一下答案,答案是还能运行 不瞒大家说, ...
- [并发并行]_[C/C++]_[C++标准库里的线程安全问题]
场景 1.写普通的程序时, 经常会使用cout来做输出, 每个进程只有一个控制台, 如果多线程调用cout时会出状况吗? 2.之所以研究cout会不会在并发下调用有问题, 是因为曾经有一个bug的崩溃 ...
- 一个线程oom,进程里其他线程还能运行吗?
线程之间互相不影响:守护线程生活周期相同 引言 这题是一个网友@大脸猫爱吃鱼给我的提问,出自今年校招美团三面的一个真题.大致如下 一个进程有3个线程,如果一个线程抛出oom,其他两个线程还能运行么? ...
随机推荐
- 算法之路 level 01 problem set
2992.357000 1000 A+B Problem1214.840000 1002 487-32791070.603000 1004 Financial Management880.192000 ...
- 01: Centos7 常用命令
1.1 centos7中防火墙相关命令 1.查看状态 1. getenforce # 查看内核防火墙状态(disabled标识关闭) 2. systemctl status f ...
- 20145321 《网络对抗技术》 MSF基础应用
20145321 <网络对抗技术> MSF基础应用 实验内容 掌握metasploit的基本应用方式以及常用的三种攻击方式的思路 主动攻击,即对系统的攻击,不需要被攻击方配合,这里以ms0 ...
- 20145311王亦徐《网络对抗技术》MAL_逆向与Bof基础
20145311王亦徐<网络对抗技术>MAL_逆向与Bof基础 实践目标 运行一个可执行文件,通过逆向或者Bof技术执行原本不应该执行的代码片段采用的两种方法: 1.利用foo函数的Bof ...
- 按时间间隔生成cron表达式
cron表达式是使用任务调度经常使用的表达式了.对于通常的简单任务,我们只需要一条cron表达式就能满足.但是有的时候任务也可以很复杂. 最近我遇到了一个问题,一条任务在开始的时候要触发A方法,在结束 ...
- ajax请求的同步异步问题
前言 在做项目的过程中遇到一个bug就是:使用了alert语句后,代码才能正确执行,没使用就执行不成功. 后来我就用把console.log,代码就不能正确执行. 于是我就去比较了下consol.lo ...
- 从bios启动说起
如果从bios启动说起的话,BIOS去加载bootloader,bootloader去加载操作系统,那么bootloader是怎么找到操作系统的呢?经过一些流程后,它会去找grub:然后通过grub提 ...
- 51NOD 1069 Nim游戏
1069 Nim游戏 有N堆石子.A B两个人轮流拿,A先拿.每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出 ...
- BZOJ2662: [BeiJing wc2012]冻结 spfa+分层图
Description “我要成为魔法少女!” “那么,以灵魂为代价,你希望得到什么?” “我要将有关魔法和奇迹的一切,封印于卡片之中„„” 在这个愿望被实现以后的世界里,人们享 ...
- Linux——权限管理命令简单笔记
首先linux中的权限分为三种rwx 代表字符 权限 对文件的含义 对目录的含义 r 读权限 可以查看文件 内容 (cat, more, head, tail) 可以列出目录中 的内容 (ls) w ...