《java.util.concurrent 包源码阅读》12 线程池系列之ThreadPoolExecutor 第二部分
接着说worker线程是如何工作的。ThreadPoolExecutor有一个成员类叫Worker,所起到的作用就是线程池worker线程的作用。
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
这里AbstractQueuedSynchronizer的作用是使Worker具有锁的功能,在执行任务时,会把Worker锁住,这个时候就无法中断Worker。Worker空闲时候是线程池可以通过获取锁,改变Worker的某些状态,在此期间因为锁被占用,Worker就是不会执行任务的。
Worker工作的逻辑在ThreadPoolExecutor#runWorker方法中
public void run() {
runWorker(this);
}
因此转到runWorker方法:
final void runWorker(Worker w) {
Runnable task = w.firstTask;
w.firstTask = null;
boolean completedAbruptly = true;
try {
// 执行分配的任务或者从BlockingQueue中等待获取任务
while (task != null || (task = getTask()) != null) {
w.lock();
clearInterruptsForTaskRun();
try {
// 执行任务之前的工作
beforeExecute(w.thread, task);
Throwable thrown = null;
// 执行任务,如果发生异常,该Worker就不会再继续执行任务
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 {
// Worker不再执行任务的处理,completedAbruptly为false
// 表示正常结束,否则表示执行任务出错。
processWorkerExit(w, completedAbruptly);
}
}
来看看processWorkerExit,重点看看执行任务发生异常时该如何处理
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 发生异常,首先要更新Worker数量
if (completedAbruptly)
decrementWorkerCount();
// 移除这个Worker
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 尝试停止线程池,正常运行的线程池调用该方法不会有任何动作
tryTerminate();
int c = ctl.get();
// 如果线程池没有被关闭的话,
if (runStateLessThan(c, STOP)) {
// Worker不是异常退出,检查worker线程数是不是小于最小值
// 这个最小值分为几种情况:
// 1. allowCoreThreadTimeOut(JDK6新加)表示是否允许线程池在超
// 过一定时间没有收到任务后退出,这种情况下,最小值为0,因为如果如
// 果一直没有任何任务,worker线程数是0
// 2. 最小值为corePoolSize,因为corePoolSize可能为0,因此这种情况
// 下,如果有任务的话必然会有Worker,因此最小值为1
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return;
}
// 如果Worker线程数小于最小值,新建一个Worker线程
addWorker(null, false);
}
}
这篇文章主要讲述了Worker线程的工作原理,接下里会讲线程池是如何进行状态切换的。
《java.util.concurrent 包源码阅读》12 线程池系列之ThreadPoolExecutor 第二部分的更多相关文章
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...
- 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验
JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...
- 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing
仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...
随机推荐
- win10 UWP 蜘蛛网效果
我看见了知乎首页登录背景和普通的地球人写的博客,发现了个好看的效果. 那么我来告诉大家如何做这个效果. 第一步是在 Canvas 画点,第二步是让点移动,第三步是画线 在 Canvas 画一个点 我们 ...
- event模拟数据库链接
from threading import Thread,Event,currentThread import time e = Event() def conn_mysql(): count = 1 ...
- HTML5之appcache语法理解/HTML5应用程序缓存/manifest缓存文件官方用法翻译
习惯性的贴几个参考链接: W3School-HTML 5 应用程序缓存 官方 MDN window.applicationCache 接口文档 官方 MDN 用法示例 看所有的教程不如直接看最原始的官 ...
- call()与apply() 改变this指向
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Consolas; color: #a5b2b9 } span.Apple-tab-span ...
- javascript编写一个简单的编译器(理解抽象语法树AST)
javascript编写一个简单的编译器(理解抽象语法树AST) 编译器 是一种接收一段代码,然后把它转成一些其他一种机制.我们现在来做一个在一张纸上画出一条线,那么我们画出一条线需要定义的条件如下: ...
- bootstrap折叠调用collapse()后data-parent不生效问题
今天做的项目,用到了bootstrap的折叠功能,这个功能需要只展开一个折叠框,点击一个就会自动隐藏另一个,初始按照API做了一下,发现一切运行正常,但是测试的同事提了一个bug,说切换到其他模块后再 ...
- HDU1255覆盖的面积
覆盖的面积 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- 必须先将 ContentLength 字节写入请求流,然后再调用 [Begin]GetResponse。解决方法
当在后台实现POST请求的时候,出现如下错误: 必须先将 ContentLength 字节写入请求流,然后再调用 [Begin]GetResponse. 或者是如下错误: 上述是因为由于我们使用的是代 ...
- 逆向知识第八讲,if语句在汇编中表达的方式
逆向知识第八讲,if语句在汇编中表达的方式 一丶if else的最简单情况还原(无分支情况) 高级代码: #include "stdafx.h" int main(int argc ...
- 《天书夜读:从汇编语言到windows内核编程》一 汇编指令与C语言
1. Debug模式下,VC++6.0下断点运行,按CTRL+F11可查看汇编代码:另外可以用cl /c /FAs YourCppFile.cpp命令行在同目录生成YourCppFile.asm汇编文 ...