线程池状态以及转换java_JAVA线程池总结一下
线程池的工作原理,以及拒绝策略,大家都很熟悉,下面主要讲一下线程池shutdown的原理,以及一些不常用操作的原理。
shutdown
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
复制代码
启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务。如果已关闭,则调用不会产生任何其他影响。此方法不等待先前提交的任务完成执行。使用awaitTermination可以做到这一点。
advanceRunState
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
复制代码
将runState转换为给定状态,或者已经存在的状态比给定状态大时将直接返回。
循环使用CAS设置状态,设置成功返回。
interruptIdleWorkers
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
复制代码
因为work每次执行任务的时候都会先lock,完成任务后unlock,
如果tryLock可以成功说明work当前没有在执行任务。使用interrupt中断空闲的work线程。
tryTerminate
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
复制代码
shutdownNow
public List shutdownNow() {
List tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
复制代码
尝试停止所有正在执行的任务,暂停正在等待的任务的处理,并返回正在等待执行的任务的列表。从此方法返回后,这些任务将从任务队列中耗尽(删除)。此方法不等待主动执行的任务终止。除了尽最大努力尝试停止处理正在执行的任务之外,没有任何保证。此实现通过中断取消任务,因此任何无法响应中断的任务都可能永远不会终止。
interruptWorkers
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
复制代码
中断所有线程,即使处于活动状态也是如此。
drainQueue
private List drainQueue() {
BlockingQueue q = workQueue;
ArrayList taskList = new ArrayList();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
复制代码
使用drainTo方法将任务队列写入新列表。但是,如果队列是DelayQueue或其他类型的队列,但poll或drainTo可能无法删除某些元素,则将它们逐个删除。
Worker
Worker主要维护运行任务线程的中断控制状态,以及其他次要簿记。此类扩展了AbstractQueuedSynchronizer,以简化获取和释放围绕每个任务执行的锁。我们实现了一个简单的非可重入互斥锁,而不是使用ReentrantLock,因为我们不希望辅助任务在调用诸如setCorePoolSize之类的池控制方法时能够重新获取该锁。另外,为了抑制直到线程真正开始运行任务之前的中断,我们将锁定状态初始化为负值,并在启动时将其清除(在runWorker中)。
runWorker
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 pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
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);
}
}
复制代码
Work反复从队列中获取任务并执行它们,同时解决许多问题:
我们可能从一个初始任务开始,在这种情况下,我们不需要第一个。否则,只要池是 运行时,我们从getTask获得任务。如果返回null,则 Work由于池状态或配置参数更改而退出。其他退出是由于引发异常 外部代码,在这种情况下,completedAbruptly为true,其通常导致processWorkerExit替换此线程。
在运行任何任务之前,先获取锁以防止在执行任务时其他池中断,然后我们确保除非池正在停止,否则此线程没有它的interrupt set。
在每次运行任务之前,都要调用beforeExecute,可能会引发异常,在这种情况下,我们导致线程死亡(中断循环,使用completelyAbruptly为true)无需处理 任务。
假设beforeExecute正常完成,我们运行 任务,收集其抛出的任何异常以发送给afterExecute。 我们分别处理RuntimeException,Error(两者 规范保证我们可以捕获)和任意Throwables。 因为我们无法在Runnable.run中抛出Throwables,所以我们 将它们包装在错误的出路(到线程的 UncaughtExceptionHandler)。 任何抛出的异常也保守地导致线程死亡。
task.run完成后,我们调用afterExecute,这可能也会引发异常,这也会导致线程 死。 根据JLS Sec 14.20,此例外是即使task.run抛出也将有效。
异常机制的net效果是afterExecute和线程的UncaughtExceptionHandler具有相同的精度 我们可以提供的有关以下方面遇到的任何问题的信息用户代码。
processWorkerExit
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate(); // shutdown状态时,每个工作线程完成工作后,终止线程池
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false); // 工作线程执行任务异常退出时,重新启动一个工作线程来完成任务
}
}
复制代码
线程池的状态
线程池的控制状态ctl是一个atomic integer。表示workCount和runState两个字段。
workerCount指示有效线程数。int的后29位表示有效线程数。
runState,指示是否正在运行,正在关闭等。int的前三位表示线程池的状态。
RUNNING: 接受新任务并处理排队的任务
SHUTDOWN: 不接受新任务,而是处理排队的任务
STOP: 不接受新任务,不处理排队任务以及中断进行中的任务
TIDYING: 所有任务已终止,workerCount为零,线程转换为状态TIDYING将运行Terminated()挂钩方法
TERMINATED: terminated()执行完成
运行状态切换
RUNNING -> SHUTDOWN: 在调用shutdown()时,可能隐式在finalize()中
(RUNNING or SHUTDOWN) -> STOP: 调用shutdownNow()
SHUTDOWN -> TIDYING: 队列和work pool为空
STOP -> TIDYING: work pool为空
TIDYING -> TERMINATED: terminated()执行完成
状态相关的一些代码
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private static final int COUNT_BITS = Integer.SIZE - 3; // 29,11101
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 29位,全是1,值 536870911
private static final int RUNNING = -1 << COUNT_BITS; // 32位,前三位是1, 值 -536870912
private static final int SHUTDOWN = 0 << COUNT_BITS; // 值 0
private static final int STOP = 1 << COUNT_BITS; // 30位,第一位是1,值 536870912
private static final int TIDYING = 2 << COUNT_BITS; // 31位,第一位是1,值 1073741824
private static final int TERMINATED = 3 << COUNT_BITS; // 31位,前两位是1, 值 1610612736
-1 // 11111111111111111111111111111111, 32位
0 // 0
1 // 1
2 // 10
3 // 11
~CAPACITY // 32位,前三位是1,11100000000000000000000000000000,值-536870912
复制代码
关于找一找教程网
本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[JAVA线程池总结一下]http://www.zyiz.net/tech/detail-140131.html
线程池状态以及转换java_JAVA线程池总结一下相关推荐
- java线程主要状态及转换_Java线程状态转换及控制
线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)这五 ...
- 利用Collections将非线程安全的Map转换成线程安全的Map
HashMap是最常用的一种Map,属于非线程安全的Map实现类.好处是效率高,因为不用考虑线程安全,任何时候都是无脑的直接操作. 在web项目中的单线程代码中,使用HashMap是没有问题的,但是一 ...
- java线程切换 notify_浅谈 Java线程状态转换及控制
作者:城北有个混子 出自:博客园 1.线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞( ...
- java线程6种状态转换,Java线程的生命周期和各种状态转换详解
在Java中,任何对象都有生命周期,线程也不例外,它也有自己的生命周期.当Thread对象创建完成时,线程的生命周期便开始了,当线程任务中代码正常执行完毕或者线程抛出一个未捕获的异常(Exceptio ...
- 线程的几种状态极其转换
线程的几种状态极其转换 线程在一定条件下,状态会发生变化.线程一共有以下几种状态: 1.初始化状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该 ...
- Java线程状态及其转换
Java线程的状态及转换 线程状态及其转换 线程的状态 详细介绍: 新建状态(NEW): 就绪状态(RUNNABLE): 运行状态(RUNNING): 阻塞状态(BLOCKED): 等待状态(WAIT ...
- 线程的状态、调度、同步
线程的状态 java中的线程共五个状态:新建.就绪.运行.阻塞.死亡: 新建状态(New):处于系统创建线程,但未启动此线程,系统未为其分配资源. 就绪状态(Runnable):线程调用start( ...
- JAVA线程六种状态_Java:线程的六种状态及转化
多线程概述及创建方式 Java:线程的六种状态及转化 关于线程的生命周期,网上书上说法不一,难以统一,本篇做一个总结: java.lang.Thread.State枚举类中定义了六种线程的状态,可以调 ...
- react 线程_React式服务中的线程本地状态可用性
react 线程 任何架构决策都需要权衡. 如果您决定采用React式,也没有什么不同,例如,一方面使用React式流实现几乎可以立即获得更好的资源利用率,但另一方面会使调试更加困难. 引入React ...
最新文章
- Mysql5.6-DDL是否加锁
- 小程序直播间页面路径怎么访问直播间_以小程序为例,在线教育产品的直播间有哪些功能设计?...
- OpenCV定制和调试检测系统
- 捕获异常VS抛出异常
- Map 的Properties集合存储IO流对象
- mysql5.0.27+apache2.0.59+php5.2.0+phpMyAdmin-2.6.4-pl3
- ECshop生态全面开放,城市合伙人招募火热启动
- Visual Studio BI 中维度的KeyColumns属性
- 基于Hadoop生态系统的一种高性能数据存储格式CarbonData(基础篇)
- 实验板FPGA型号在哪里看_【VE】一文看懂乙烯基树脂发展史!
- GAT1400---基于libcurl库的开发
- 离散概率分布的介绍及Python运用
- 纸的大小图解_手工折纸大全图解 不一定是A4大小)一般都有7
- mysql idb恢复_MySQL 通过idb文件恢复Innodb 数据【转】
- HMI-41-【节能模式】右侧表小汽车灯光实现
- 【汇编程序】编写一个在显示器上显示的一个笑脸字符的程序
- java菜鸟快速上手指南
- html5 扫描条码,原 HTML5+规范:barcode(条码扫描)
- uniapp - 电商优购项目
- 柱形图和折线图在一个坐标轴ECharts
热门文章
- delphi5开发人员指南_成为企业家并发挥作用的开发人员指南
- 136_Power BI 自定义矩阵热力图
- 仅需1秒!搞定100万行数据:超强Python数据分析利器
- 两本电子书 |Flink 最佳学习实践 | 从 0 到 1 学会 Apache Flink
- Python类属性、类方法和静态方法
- 通过c# 实现自定义属性改变触发自定义事件 ,理解自定义事件及其触发过程
- 服务器IIS asp.net中.aspx映射
- MVC教程第四篇:传递表单数据
- Asp.Net ListView 控件的使用
- 漫步微积分三十五——弧长