接着说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 第二部分的更多相关文章

  1. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  2. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  3. 《java.util.concurrent 包源码阅读》04 ConcurrentMap

    Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...

  4. 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包

    Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...

  5. 《java.util.concurrent 包源码阅读》17 信号量 Semaphore

    学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...

  6. 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue

    对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...

  7. 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

    concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...

  8. 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验

    JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...

  9. 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing

    仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...

随机推荐

  1. 设置QT应用程序图标方法(Windows下)

    学习笔记,言简意赅. 1- 新建文本文件,编辑输入  IDI_ICON1   ICON    DISCARDABLE     "./image/WindowIco.ico" 注意: ...

  2. UVa12100,Printer Queue

    水题,1A过的 数据才100,o(n^3)都能过,感觉用优先队列来做挺麻烦的,直接暴力就可以了,模拟的队列,没用stl #include <iostream> #include <c ...

  3. Java 线程基本知识

    线程 线程和进程 进程 : 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程 : 线程是进程中的一个执行单元(执行路径 ...

  4. ReflectiveLoader分析(远程线程注入 PE修正)

    从github上下载了ReflectiverLoader认真学习了一下 在代码中得到一些心得和自己的想法,都按步骤写到了代码中,现在分享给大家,如有错,望大家指正 其中需要注入的dll和解析, 内存R ...

  5. h5样式初始化

    nav, header, section, article, aside, footer { display: block; } body, p, pre, hr, ul, dl, dd, h1, h ...

  6. LeetCode 370. Range Addition (范围加法)$

    Assume you have an array of length n initialized with all 0's and are given k update operations. Eac ...

  7. NotePad++ 正则表达式替换 高级用法 [转]

    转自:http://blog.csdn.net/gdp12315_gu/article/details/51730584 在我们处理文件时,很多时候会用到查找与替换.当我们想将文件中某一部分替换替换文 ...

  8. Install a Jenkins on Ubuntu system

    ================================================================================ Jenkins Environment ...

  9. Linux系列教程(十一)——Linux软件包管理之RPM命令

    前面我们介绍了Linux系统的常用命令介绍和文本编辑器vim命令的介绍.那么从这篇博客开始,我们会正式的讲解Linux的系统管理,首先要讲的是Linux的软件包管理. 1.Linux软件包分类 一.源 ...

  10. 1041: [HAOI2008]圆上的整点

    1041: [HAOI2008]圆上的整点 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4298  Solved: 1944[Submit][Sta ...