Java线程池源码分析

文章目录概述类结构详细解析构造函数一些成员变量关于线程池状态添加一个任务之后发生了什么?execute()方法概述线程是稀缺资源,如果线程被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,所以合理的使用线程池对线程进行统一分配、调优和监控,有巨大的好处。降低资源消耗提高系统响应速度提高线程可管理性JDK1.5引入了Executor线程池框架,通过把任务的提交和执行进行解耦,...
摘要由CSDN通过智能技术生成

概述

线程是稀缺资源,如果线程被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,所以合理的使用线程池对线程进行统一分配、调优和监控,有巨大的好处。

  • 降低资源消耗
  • 提高系统响应速度
  • 提高线程可管理性

JDK1.5引入了Executor线程池框架,通过把任务的提交和执行进行解耦,我们只需要定义好任务(Runnable),然后将它提交给线程池,而不用关心该任务是如何执行、被哪个线程执行以及什么时候执行。

类结构

Java线程池相关类库全部位于java.util.concurrent包下,类结构如下图:
在这里插入图片描述

  • Executor : 是最顶层接口,它只包含一个方法execute()
  • ExecutorService : 继承自Executor接口,在Executor接口基础上添加了submit()(关于execute与submit区别,会在本文后边详细叙述)方法,并添加了若干线程池状态(关于线程池状态,会在本文后边详细叙述)操作方法,如shutdown(),shutdownNow()等。
  • AbstractExecutorService : 继承自ExecutorService,并实现了ExecutorService的若干方法,如submit()等。
  • ThreadPoolExecutor : 继承于AbstractExecutorService,是线程池的核心类,几乎所有与线程池有关的逻辑都封装在这个类里边。
  • DiscardPolicy、DiscardOldestPolicy、AbortPolicy、CallerRunsPolicy : 四种饱和策略。
  • Worker : 线程池真正的线程类,本身实现了Runnable接口和AQS(AbstractQueuedSynchronizer)接口。

详细解析

构造函数

总共有四个,分别为

//1
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)
//2
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
//3                              ThreadFactory threadFactory)
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler)
//4
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

构造函数主要是对线程池参数的初始化,关于线程池参数可以参考另外一篇文章Java线程池参数解析。其中构造函数1-3最后都是调用到了构造函数4,简单分析一下4即可。

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;
}
  • 首先,对各个数值型参数做校验,校验规则为 : (1) corePoolSize < 0 (2) maximumPoolSize <=0 (3) maximumPoolSize < corePoolSize (4) keepAliveTime < 0,以上情况均抛出IllegalArgumentException异常。
  • 然后,对阻塞队列、线程工厂、饱和策略判空,任一项为空则抛出NullPointerException异常。
  • 最后,通过校验之后,将各个参数值赋值给ThreadPoolExecutor实例的相应成员变量。

一些成员变量

由于corePoolSize、maximumPoolSize等线程池参数已经在博客Java线程池参数解析有过叙述,故此处不再赘述。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

ctl是线程池中一个非常重要的变量,以它的低29位表示线程池中处于RUNNING状态的线程个数,高3位表示线程池所处的状态(关于线程池的状态我们待会再讲)。

private static final int COUNT_BITS = Integer.SIZE - 3;

COUNT_BITS表示RUNNING状态下的线程数对应二进制的位数,也就是29。

private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

CAPACITY用于与ctl做与运算,得到RUNNING状态下线程的个数。CAPACITY的值为

000111111111111111111111111111111
private static final int RUNNING    = -1 << COUNT_BITS;

RUNNING表示线程池的运行状态,可处理新任务并执行队列中的任务,十进制表示为-536870912。二进制表示为

11100000000000000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;

SHOTDOWN表示线程池的关闭态,不接受新任务,但处理队列中的任务,值为0。

private static final int STOP       =  1 << COUNT_BITS;

STOP表示线程池的停止态,不接受新任务,不处理队列中任务,且打断运行中任务,十进制表示为536870912。二进制表示为

00100000000000000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;

TIDYING表示线程池的整理态,所有任务已经结束,workerCount = 0 ,将执行terminated()方法,值为1073741824。二进制表示为

01000000000000000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

TERMINATED表示线程池的结束态,terminated() 方法已完成,值为1610612736。二进制表示为

01100000000000000000000000000000

不难发现,在所有的五种状态中SHUTDOWN值等于0,RUNNING值小于0,其他三种状态STOP、TIDYING、TERMINATED值均大于0。

private final HashSet<Worker> workers = new HashSet<Worker>();

workers用于存储真正运行的任务Worker(后边我们会详细讲述Worker的运行原理)。

private volatile boolean allowCoreThreadTimeOut;

allowCoreThreadTimeOut用于表示核心线程在空闲一定时间之后是否过期。

关于线程池状态

为了更好的管理线程,Java线程池总共包含五种状态。要注意的是,线程池的状态要与线程的状态区别开来,这两者之间没有什么必然的联系。具体请看下图
在这里插入图片描述

  • RUNNING : 运行态,也是线程池的默认状态,当new一个ThreadPoolExecutor实例之后,这个ThreadPoolExecutor的状态就是运行态。运行态能够接受新添加任务,也能够对阻塞队列中的任务进行处理。
  • SHOWDOWN : 关闭态,当调用ThreadPoolExecutor实例的showdown()方法之后,这个ThreadPoolExecutor实例就会进入关闭态。关闭态能够对阻塞队列中的任务进行处理,不能够接受新添加的非空任务,但是可以接受新添加的空任务。
  • STOP : 停止态,当调用ThreadPoolExecutor实例的shutdownNow()方法之后,这个ThreadPoolExecutor实例就会进入停止态。停止态不能接受新添加任务,也不能够对阻塞队列中的任务进行处理,并且会中断正在运行的任务。
  • TIDYING : 整理态,当线程池中所有任务已被终止, 这个ThreadPoolExecutor实例就会进入停止态。
  • TERMINATED : 结束态,当线程池处于整理态,并调用terminated()方法,执行完毕之后,就会进入结束态,此状态也表示整个线程池生命周期的结束。

了解线程池的五个状态,对于理解线程池的工作原理至关重要,它是基础中的基础,所以在读线程池源码前一定要了解一下它们。

添加一个任务之后发生了什么?

接下来,我们主要分析一下execute()方法,也就是添加一个Runnable任务之后,到底发生了什么?

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();
        }
        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 (!addWo
  • 14
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值