上篇博客java线程(5)——线程池(上)介绍了线程池的基本知识,这篇博客我们介绍一下常用的ThreadPoolExecutor。


定义

类图关系:

ThreadPoolExecutor继承了AbstractExecutorService抽象类,而AbstractExecutorService实现了ExecutorService接口。

下面来看下ThreadPoolExecutor的代码:

public class ThreadPoolExecutor extends AbstractExecutorService {

   //核心线程池的大小。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
private volatile int corePoolSize; //线程池中线程的最大数量
private volatile int maximumPoolSize; //Timeout时间,没有任务执行时最多保持多久时间之后终止。
private volatile long keepAliveTime; //线程工厂,所有的线程都是通过他创建的。
private volatile ThreadFactory threadFactory;
...... //给定初始化参数
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;
}
......
}

Tips:

Volatile关键字,意为“不稳定的,易变的”。它经常用在多线程中的类型修饰符,他的作用是确保某条指令或代码不会被省略,而且每次都是直接读取值,而不是使用备份数据。

线程池状态

线程池的几种状态基本上是级别层层递进的,区分的因素有:

是否接受新任务,

是否允许运行队列中的任务,

是否继续执行正在处理的任务等等。

   //线程池能接受任务新任务,并且可以运行队列中的任务
private static final int RUNNING = -1 << COUNT_BITS; //不再接受新任务,但可继续运行队列中的任务
private static final int SHUTDOWN = 0 << COUNT_BITS; //任务都不再执行,正在处理的任务要中断
private static final int STOP = 1 << COUNT_BITS;
//终止
private static final int TIDYING = 2 << COUNT_BITS;
//terminated()方法执行结束
private static final int TERMINATED = 3 << COUNT_BITS;

状态之间的转化关系图如下:

Worker类

说到线程池,我们经常会把线程池比作是一个工厂,而把线程比作工人。

在ThreadPoolExecutor类中,还真就有一个Worker类,先看一下他的定义。

 private final class Worker  extends AbstractQueuedSynchronizer implements Runnable{
//正在运行
final Thread thread;
//初始运行的任务,可能为null
Runnable firstTask;
//前一个线程任务
volatile long completedTasks; Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
} //检查是否可以添加新的线程到当前的线程池中
private boolean addWorker(Runnable firstTask, boolean core) { }
//创建线程时失败回滚
private void addWorkerFailed(Worker w) {
} //移除任务
public boolean remove(Runnable task) {
}
...... }

分析:

Worker继承了AbstractQueuedSynchronizer,他是一个基于FIFO队列,也叫同步器。

Worker类实现了Runnable接口,说明他是一个线程类。此外,内部还提供了新增、移除任务等方法。那么什么时候可以新增什么时候又需要移除呢,就涉及到核心方法execute()了。

execute()

核心代码如下:

 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();
}
//如果当前线程池状态为running,且成功加入指定队列
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);
}
else if (!addWorker(command, false))
reject(command);
}

分析:

上面的代码由三个大的if块组成,前两个比较容易理解,第三个有点绕。

1、当前活动线程<核心池大小,继续调用addWorker创建线程处理任务。

2、前面说到Running状态可以接受新任务,运行队列中的任务。判断当前线程的状态是否为Running,如果是,并且任务成功加入队列,还需要进行二次检查,防止出现shut down现象。

3、如果当前线程状态不是Running或任务加入队列失败,则跳转到else if中,执行reject()方法。

java线程(6)——线程池(下)的更多相关文章

  1. java 多线程 4 线程池

    系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...

  2. (转)java自带线程池和队列详细讲解 - CSDN过天的专栏

    一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util ...

  3. Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  4. Java四种线程池

    Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:20 ...

  5. java自带线程池和队列详细讲解

    Java线程池使用说明 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后 ...

  6. java并发:线程池、饱和策略、定制、扩展

    一.序言 当我们需要使用线程的时候,我们可以新建一个线程,然后显式调用线程的start()方法,这样实现起来非常简便,但在某些场景下存在缺陷:如果需要同时执行多个任务(即并发的线程数量很多),频繁地创 ...

  7. java笔记--使用线程池优化多线程编程

    使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库 ...

  8. Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void ru ...

  9. Java多线程之线程池

    现在是多核的时代,面向多核的编程很重要,因此基于java的并发和多线程开发非常重要. 线程池是于队列密切相关的,其中队列保存了所有等待执行的任务.工作者线程的任务很简单:从队列中获取一个任务,执行任务 ...

  10. Java多线程和线程池

    转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...

随机推荐

  1. eclipse 突然debug模式不能正常运行了

    eclipse 突然debug模式不能正常运行了,但非debug模式却能正常运行.debug模式不能正常启动的现象描述如下:    点击eclipse debug按钮,console窗口显示tomca ...

  2. Java入门(一)

    一.语言分类 机器语言 汇编语言 高级语言 二.Java分类 JavaSE 标准版,主要针对桌面应用 JavaEE 企业版,主要针对服务器端的应用 JavaME 微型版,主要针对消费性电子产品的应用 ...

  3. mysql 如何监控innodb的阻塞

  4. 快速玩转linux(1)

    快速上手Linux玩转典型应用 mark 大牛都会使用Linux, Linux命令是行业要求. 商业服务器基本都是linux 开源软件都先支持Linux(只支持) 大数据分析.机器学习首选Linux ...

  5. 【解决】MongoDB 线上业务处理,数据去重脚本实现

    mongo客户端工具下载  https://robomongo.org/download   线上业务,k线 展示出现问题,相同时间戳的数据多次插入导致数据不真实,后经排查发现是每次都是写的四条数据, ...

  6. php实现redis

    <?php //实例化Redis对象 $red=new Redis(); //链接redis服务 $red->connect('localhost','6379'); //具体操作 $re ...

  7. QOS-QOS(服务质量)概述

    QOS-QOS(服务质量)概述 2018年7月7日  20:29 概述及背景: 1.  引入: 传统IP网络仅提供“尽力而为”的传输服务,网络有可用资源就转发,资源不足时就丢弃 新一代IP网络承载了 ...

  8. rhel6.4 根目录扩容

    状况:根目录容量不足 解决:扩容根目录 ====================================================== 解决步骤: 1. 将新的磁盘加入服务器 2. 使用 ...

  9. react ant-design自定义图标

    ant-design给我们提供的图标不够怎么办呢?答案是我们可以自定义图标. 自定义图标也挺简单的,现在图标推荐用svg格式,那么我们就需要制作svg图片. 下面让我们看看如果制作svg图片吧. 1. ...

  10. python的初体验

    最近由于毕业答辩,导致一些博客没有更新,见谅,今天我们开始一些新的内容 1.python的注释 单行注释:# 多行注释: ''' 这是多行注释 我们可以在里面写很多很多的行 ''' 2.编码风格 #c ...