这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭。

先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法:

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException(); this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

可以看到,尽管设定了corePoolSize,也就是Worker线程的数量,但是线程池开启的时候,默认是没有创建这些Worker线程的,但是ThreadPoolExecutor提供了prestartAllCoreThreads方法来开启所有的预设的Worker线程,以及prestartCoreThread尝试开启一个预设的Worker线程。

这里重点说说handler,也就是RejectedExecutionHandler,拒绝任务的处理类,ThreadPoolExecutor提供四种策略:

1. CallerRunsPolicy

该策略会在ThreadPoolExecutor没有关闭的情况,依旧运行任务

2. AbortPolicy

该策略会抛出一个RejectedExecutionException

3. DiscardPolicy

该策略直接忽略该任务,不会有任何动作

4. DiscardOldestPolicy

该策略会在ThreadPoolExecutor没有关闭的情况,丢弃下一个将要执行的任务,把该任务加入到执行队列。

接下来说说关闭,ThreadPoolExecutor提供了shutdown和shutdownNow两种方式,从字面上就能看出区别,后者会尝试结束正在运行的任务。

先来看shutdown:

    public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // ScheduledThreadPoolExecutor的回调方法
} finally {
mainLock.unlock();
}
tryTerminate();
}

再看shutdownNow:

    public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}

两个方法的代码非常相似,区别在于:

1. shutdownNow的状态设置为STOP,shutdown的状态是SHUTDOWN

2. shutdownNow会中断所有线程,也就是所有任务,而shutdown仅仅中断空闲线程,不会影响正在执行的任务。

3. shutdownNow会导出未执行的任务。

两个方法都用到的checkShutdownAccess方法主要是检查方法调用者是否有权限中断Worker线程。

advanceRunState方法用于设定线程的状态,如果状态值大于等于该状态值则会返回。关于状态值参看 《java.util.concurrent 包源码阅读》11 线程池系列之ThreadPoolExecutor 第一部分。

关于interruptIdleWorkers和interruptWorkers,在上一篇文章曾经说过Worker线程具备锁的功能,因此可以通过tryLock来判断Worker线程是否处于空闲状态,这是两个方法的区别所在。

这一部分写的有些凌乱,各位见谅。

《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 《java.util.concurrent 包源码阅读》25 Fork/Join框架之Fork与Work-Stealing(重写23,24)

    在写前面两篇文章23和24的时候自己有很多细节搞得不是很明白,这篇文章把Fork和Work-Stealing相关的源代码重新梳理一下. 首先来看一些线程池定义的成员变量: 关于scanGuard: v ...

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

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

随机推荐

  1. Python学习笔记(十三)

    Python学习笔记(十三): 模块 包 if name == main 软件目录结构规范 作业-ATM+购物商城程序 1. 模块 1. 模块导入方法 import 语句 import module1 ...

  2. MAVEN 打包JAR

    <build> <finalName>edu-service-user</finalName> <resources> <resource> ...

  3. Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案

    Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...

  4. 使用速卖通开放平台云API调用菜鸟组件实现云打印

    公司是跨境电商,使用速卖通平台卖玩具,我们自己研发的ERP是基于速卖通开放平台API,实现订单的发货提交,打印面单等功能 近期公司要求使用菜鸟组件云打印,去平台里看下,有这个API,如下图所示 实现也 ...

  5. Python中如何防止sql注入

    sql注入中最常见的就是字符串拼接,研发人员对字符串拼接应该引起重视,不应忽略. 错误用法1: sql = "select id, name from test where id=%d an ...

  6. JavaWeb之Eclipse中使用Maven构建SpringMVC项目

    为了学习spring和maven我这也是拼了老命了,光使用maven配置springmvc我花了上周一周的时间,下班回来就搞,一直有bug,一个bug接着一个,昨天一整天都在解决配置的问题,让大学同学 ...

  7. js 判断通过什么打开(安卓、苹果、微信、QQ、浏览器、某个app应用…)

    /* 获取当前环境: 系统环境: iOS Android PC 浏览器环境 微信内置浏览器.QQ内置浏览器.正常浏览器 是否app内打开 */ var ua = navigator.userAgent ...

  8. fastDFS文件服务器迁移

    在实际的项目应用中,由于服务器替换或项目变更难免会存在fastDFS文件服务器迁移的工作.本文重点介绍fastDFS文件系统在不同情况下的文件迁移处理方案. 1.迁移时IP地址不变 通过文件服务器存储 ...

  9. hbase-1.2.5完全分布式部署

    详细配置参考http://abloz.com/hbase/book.html#distributed ,2.2.2.2小节 1.修改hbase-site.xml文件.添加如下配置 cluster为ha ...

  10. Leetcode题解(21)

    62. Unique Paths 题目 分析: 机器人一共要走m+n-2步,现在举个例子类比,有一个m+n-2位的二进制数,现在要在其中的m位填0,其余各位填1,一共有C(m+n-2,m-1)种可能, ...