线程池源码撸完,面试还怕被问线程池?

前言

大家好,我是努力更文的小白,我们知道不论是面试还是工作当中,都会接触到线程池,线程池更是面试官爱问的知识点,今天我带着大家来看一看线程池的源码,虽然看源码是一件十分枯燥无味的事情,但是你不卷,总有人卷,谁也不甘心被优化!!!跟着我,卷起来!!!

继承体系

线程池的继承体系如下图所示

image.png

线程池状态

线程池状态转换如下图所示

image.png

  • 首先创建出线程池,并且没有调用shutdown方法之前,线程池就处于正常的运行状态,即RUNNING。处于RUNNING状态的线程池,你提交的任务(调用submit或者execute方法)才会被线程池执行,处于RUNNING状态的线程池能接受新提交的任务,并且也能处理阻塞队列中的任务。

  • 处于RUNNING状态的线程池调用shutdown方法之后,线程池的状态就会变成SHUTDOWN,此时你再提交新的任务(调用submit或者execute方法)就会被线程池拒绝掉。但是SHUTDOWN状态的线程池有一个特殊的点:它不是会将所有的线程立马退出,而是将之前任务队列中的任务都执行完之后线程才会依次退出。

  • 处于STOP状态的线程池不能接受新提交的任务,也不能处理阻塞队列中的任务,会中断正在处理任务的线程。当线程池处于RUNNING或者SHUTDOWN状态时,调用shutdownNow方法就会线程池就会进入该状态。

  • 当所有的任务都终止了,线程池中的线程数workCount0时,线程池就会进入TIDYING状态

  • 最后一个退出的线程(即执行完任务队列中的最后一个任务后),最后一个退出的线程会把线程池的状态变成TIDYING,然后调用terminated方法,线程池就会变成TERMINATED状态了。

拒绝策略

四种拒绝策略如下:

  • AbortPolicy:抛出一个异常,默认的(比较常用)
  • CallerRunsPolicy:交给线程池调用所在的线程进行处理
  • DiscardPolicy:直接丢弃任务
  • DiscardOldestPolicy:丢弃队列里最老的任务,将当前这个任务继续提交给线程池

属性

//高3位:表示当前线程池运行状态   除去高3位之后的低位(29位):表示当前线程池中所拥有的线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//表示在ctl中,低COUNT_BITS位 是用于存放当前线程数量的位。COUNT_BITS的值为29
private static final int COUNT_BITS = Integer.SIZE - 3;
//低COUNT_BITS位 所能表达的最大数值。 000 11111111111111111111 => 5亿多。
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
//-1就是32个1来表示的,左移29位,后面补零,即只剩下三个1和29个0
//111 000000000000000000  转换成整数,其实是一个负数
private static final int RUNNING    = -1 << COUNT_BITS;
//000 000000000000000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;
//001 000000000000000000
private static final int STOP       =  1 << COUNT_BITS;
//010 000000000000000000
private static final int TIDYING    =  2 << COUNT_BITS;
//011 000000000000000000
private static final int TERMINATED =  3 << COUNT_BITS;

//任务队列,当线程池中的线程达到核心线程数量时,再提交任务 就会直接提交到 workQueue
//workQueue  instanceOf ArrayBrokingQueue   LinkedBrokingQueue  同步队列
private final BlockingQueue<Runnable> workQueue;

 
//线程池全局锁,增加worker(线程) 减少 worker(线程) 时需要持有mainLock , 修改线程池运行状态时,也需要。
private final ReentrantLock mainLock = new ReentrantLock();

/**
 * Set containing all worker threads in pool. Accessed only when
 * holding mainLock.
 */
//线程池中真正存放 worker->thread 的地方。
private final HashSet<Worker> workers = new HashSet<Worker>();

/**
 * Wait condition to support awaitTermination
 */
//当外部线程调用  awaitTermination() 方法时,外部线程会等待当前线程池状态为 Termination 为止。
//等待是如何实现的? 就是将外部线程 封装成 waitNode 放入到 Condition 队列中了, waitNode.Thread 就是外部线程,会被park掉(处于WAITING状态)。
//当线程池 状态 变为 Termination时,会去唤醒这些线程。通过 termination.signalAll() ,唤醒之后这些线程会进入到 阻塞队列,然后头结点会去抢占mainLock。
//抢占到的线程,会继续执行awaitTermination() 后面程序。这些线程最后,都会正常执行。
//简单理解:termination.await() 会将线程阻塞在这。
//         termination.signalAll() 会将阻塞在这的线程依次唤醒
private final Condition termination = mainLock.newCondition();

/**
 * Tracks largest attained pool size. Accessed only under
 * mainLock.
 */
//记录线程池生命周期内 线程数最大值
private int largestPoolSize;

/**
 * Counter for completed tasks. Updated only on termination of
 * worker threads. Accessed only under mainLock.
 */
//记录线程池所完成任务总数 ,当worker(线程)退出时会将 worker完成的任务累积到completedTaskCount
private long completedTaskCount;


 
//创建线程时会使用 线程工厂,当我们使用 Executors.newFix...  newCache... 创建线程池时,使用的是 DefaultThreadFactory
//一般不建议使用Default线程池,推荐自己实现ThreadFactory
private volatile ThreadFactory threadFactory;

/**
 * Handler called when saturated or shutdown in execute.
 */
//拒绝策略,juc包提供了4中方式,默认采用 Abort..抛出异常的方式。
private volatile RejectedExecutionHandler handler;

 
//空闲线程存活时间,当allowCoreThreadTimeOut == false 时,会维护核心线程数量内的线程存活,超出核心线程数量的部分会被回收。
//allowCoreThreadTimeOut == true 核心数量内的线程 空闲时 也会被回收。
private volatile long keepAliveTime;

/**
 * If false (default), core threads stay alive even when idle.
 * If true, core threads use keepAliveTime to time out waiting
 * for work.
 */
//控制核心线程数量内的线程 是否可以被回收。true 可以,false不可以。
private volatile boolean allowCoreThreadTimeOut;

/**
 * Core pool size is the minimum number of workers to keep alive
 * (and not allow to time out etc) unless allowCoreThreadTimeOut
 * is set, in which case the minimum is zero.
 */
//核心线程数量限制。
private volatile int corePoolSize;

/**
 * Maximum pool size. Note that the actual maximum is internally
 * bounded by CAPACITY.
 */
//线程池最大线程数量限制。
private volatile int maximumPoolSize;

/**
 * The default rejected execution handler
 */
//缺省拒绝策略,采用的是AbortPolicy 抛出异常的方式。
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
复制代码
  • ctl:高3位:表示当前线程池运行状态(runState),除去高3位之后的低位(29位):表示当前线程池中所拥有的线程数量(workerCount)。

  • COUNT_BITS:值为29(Integer.SIZE - 3 = 32 - 3 = 29),表示在ctl中,低COUNT_BITS位 是用于存放当前线程数量的位。

  • CAPACITY:低COUNT_BITS位所能表达的最大数值。 000 11111111111111111111 => 5亿多。

  • RUNNING:表示线程池处于正常运行状态,-1就是321来表示的,左移29位,后面补零,即-1 << COUNT_BITS只剩下三个1290,即111 000000000000000000,转换成整数,其实是一个负数。

  • SHUTDOWN:表示线程池处于SHUTDOWN状态,同理0 << COUNT_BITS,即000000000000000000....,即就是0

  • STOP:表示线程池处于STOP状态,同理1 << COUNT_BITS,即001 000000000000000000.....

  • TIDYING:表示线程池处于TIDYING状态,同理2 << COUNT_BITS,即010 000000000000000000.....

  • TERMINATED:表示线程池处于TERMINATED状态,同理3 << COUNT_BITS,即011000000000000000000.....

  • workQueue:任务队列,当线程池中的线程达到核心线程数量时,再提交任务 就会直接提交到 workQueue,任务队列的实现有ArrayBrokingQueueLinkedBrokingQueue等等。

  • mainLock:线程池全局锁,增加worker(线程) 减少 worker(线程) 时需要持有mainLock , 修改线程池运行状态时,也需要。

  • workers:线程池中会把线程都封装成workerworkers真正存放所有的worker,即存放所有的线程。

  • largestPoolSize:记录线程池生命周期内 线程数最大值。

  • completedTaskCount:记录线程池所完成任务总数 ,当worker(线程)退出时会将 worker完成的任务累积到completedTaskCount

  • threadFactory:创建线程时会使用 线程工厂,一般不建议使用默认的,推荐自己实现ThreadFactory

  • handler:拒绝策略,juc包提供了4中方式。

    • AbortPolicy:抛出一个异常,默认的(比较常用)
    • CallerRunsPolicy:交给线程池调用所在的线程进行处理
    • DiscardPolicy:直接丢弃任务
    • DiscardOldestPolicy:丢弃队列里最老的任务,将当前这个任务继续提交给线程池
  • keepAliveTime:空闲线程存活时间,当allowCoreThreadTimeOut == false 时,会维护核心线程数量内的线程存活,超出核心线程数量的部分会被回收;allowCoreThreadTimeOut == true 核心数量内的线程 空闲时 也会被回收。

  • allowCoreThreadTimeOut:控制核心线程数量内的线程 是否可以被回收。true 可以,false不可以。

  • corePoolSize:核心线程数量限制

  • maximumPoolSize:线程池最大线程数量限制。

  • defaultHandler:默认的拒绝策略,采用的是AbortPolicy 抛出异常的方式。

小方法

常用的小方法源码如下:

// Packing and unpacking ctl
//获取当前线程池运行状态,即获取ctl的高三位的值+29个0
// 将ctl的值 & ~CAPACITY  CAPACITY为高三位为0,低29位为1,即000 11111111111111111111
//~000 11111111111111111111 => 111 000000000000000000000
//c == ctl = 111 000000000000000000111
//111 000000000000000000111
//111 000000000000000000000
//111 000000000000000000000
private static int runStateOf(int c)     { return c & ~CAPACITY; }

//获取当前线程池线程数量
//c == ctl = 111 000000000000000000111
//111 000000000000000000111
//000 111111111111111111111
//000 000000000000000000111 => 7
private static int workerCountOf(int c)  { return c & CAPACITY; }

//用在重置当前线程池ctl值时  会用到
//rs 表示线程池状态   wc 表示当前线程池中worker(线程)数量
//rs:111 000000000000000000
//     |
//wc:000 000000000000000111
//=
//111 000000000000000111
private static int ctlOf(int rs, int wc) { return rs | wc; }

/*
 * Bit field accessors that don't require unpacking ctl.
 * These depend on the bit layout and on workerCount being never negative.
 */
//比较当前线程池ctl所表示的状态,是否小于某个状态s
//c = 111 000000000000000111 <  000 000000000000000000 == true
//所有情况下,RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
private static boolean runStateLessThan(int c, int s) {
    return c < s;
}

//比较当前线程池ctl所表示的状态,是否大于等于某个状态s
private static boolean runStateAtLeast(int c, int s) {
    return c >= s;
}

//小于SHUTDOWN 的一定是RUNNING。 SHUTDOWN == 0
private static boolean isRunning(int c) {
    return c < SHUTDOWN;
}

//使用CAS方式 让ctl值+1 ,成功返回true, 失败返回false
//将ctl的低29位即线程数量+1
private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值