Java多线程——ThreadPoolExecutor源码解读

每次使用线程池时都会有这样那样的疑惑,通过线程池源码的解读得以解惑
对源码的解析按照线程池的域、相关概念、线程池状态、常用方法、线程池的worker、常见疑问几个方面来探索

常见疑问
  • 如何在一个任务执行完毕后不结束?

    线程池中的线程独立存在,循环的调用执行目标任务的run方法

  • 如何在没执行任务的时候保持阻塞?

    从阻塞队列中获取任务,queue.take获取不到时会阻塞

线程池的域
名字备注是否需要主锁发布情况
ctl控制运行状态、有效的线程数
workQueue工作队列
mainLock主锁
workers包含所有工作线程
termination等待支持awaitTermination的条件
largestPoolSize最大线程池大小
completedTaskCount已完成的工作数量
threadFactory线程工厂
handler拒绝策略
keepAliveTime存活保持时间
allowCoreThreadTimeOut为否时关键线程也会结束
corePoolSize关键线程数量
defaultHandler默认拒绝策略((default)AbortPolicy)
maximumPoolSize线程池最大数量
相关概念
  • Core and maximum pool sizes(核心和最大线程数)

    新任务
    开始
    大于核心线程数
    新建核心线程执行任务
    队列不满
    加入队列
    是否大于最大线程数
    新建非核心线程执行任务
    抛弃策略
  • Keep-alive times(最大持续时间)

    • 多余核心线程数的线程空闲存活时间
    • allowCoreThreadTimeOut设置后核心线程数空闲后的存活时间
  • Queuing(排队)

    存活的线程数大于核心线程数时加入队列排队

    队列分类

    • 直接交付(SynchronousQueue)

      不排队,直接新建线程来执行

    • 无界队列(LinkedBlockingQueue)

      队列永远不会满,此时核心线程数可以和最大线程数一样

    • 有边队列(ArrayBlockingQueue)

  • Rejected tasks(拒绝任务)

    拒绝情况

    • 队列已满且线程超过最大线程数

    • 线程池已经被停止

    拒绝策略(默认放弃)

    • AbortPolicy–抛出拒绝执行异常RejectedExecutionException
    • CallerRunsPolicy–调用execute方法的线程来执行
    • DiscardPolicy–直接拒绝
    • DiscardOldestPolicy–如果线程池没有停止,删除工作队列头部的任务,然后重试执行
线程池状态
shutdown
shutdownNow
shutdownNow
队列与线程池为空
线程池为空
结束的hook方法完成
RUNNING
SHUTDOWN
STOP
TIDYING
TERMINATED

在外部只能获取其RUNNING、TERMINATED、非RUNNING状态

常用方法详解
公有方法
  • public void execute(Runnable command)

    在未来的某一时刻执行任务

    1. 小于核心线程数大小的线程在运行时,新增一个线程并将该任务当作其第一个将要执行的任务
    2. 当大于核心线程数时,尝试添加到阻塞队列中
    3. 无法添加到阻塞队列时,尝试添加一个新线程,添加失败则拒绝
  • public void shutdown()

    有序关闭,先前提交的任务会被继续执行,但不会接受新任务

    1. 设置线程池状态为SHUTDOWN
    2. 停止空闲线程
  • public List shutdownNow()

    停止所有正在执行的线程并返回等待被执行的任务

    1. 设置线程池状态为STOP
    2. 停止所有工作线程
    3. 返回等待队列中的任务
  • public boolean isShutdown()

    非RUNNING状态

  • public boolean isTerminating()

    SHUTDOWN/STOP/TIDYING状态

  • public boolean isTerminated()

    TERMINATED状态

  • public boolean awaitTermination(long timeout, TimeUnit unit)

    等待一段时间后结束

    1. 线程池已经是TERMINATED状态则返回true
    2. 等待时间结束,返回false
  • public void setCorePoolSize(int corePoolSize)

    设置核心线程数

    1. 如果当前新的核心线程数<原来的核心线程数则中止线程当它们执行完任务
    2. 如果新的核心线程数>原来的核心线程数,并且等待队列中有待执行的任务,则新增核心线程执行等待任务
  • public boolean prestartCoreThread()

    提前开始一个核心线程

  • public int prestartAllCoreThreads()

    开始所有核心线程

  • public void allowCoreThreadTimeOut(boolean value)

    允许核心线程超时停止

    1. 设置allowCoreThreadTimeOut为true
    2. 停止线程当他们执行完任务之后
  • public void setMaximumPoolSize(int maximumPoolSize)

    设置最大线程数

    1. 设置最大线程数为新的最大线程数
    2. 若新的最大线程数小于原来的最大线程数,则停止工作线程在他们执行完任务之后
  • public void purge()

    尝试移除所有的被取消的Future任务

非公有方法
  • private boolean addWorker(Runnable firstTask, boolean core)

    1. 从线程工厂获取线程,并将firstTask传入作为初始执行任务
    2. 添加到workers
    3. 开始执行线程
  • private void advanceRunState(int targetState)

    设置线程池状态为SHUTDOWNSTOP

  • private void interruptIdleWorkers(boolean onlyOne)

    将空闲线程设置为中断状态

    判断空闲线程标准:tryLock方法是否成功

  • private void interruptWorkers()

    中断所有线程

  • private List drainQueue()

    将任务队列放入新的集合中,如果是延时队列或者poll方法失败的队列则删除这些

  • final void tryTerminate()

    开始
    线程池在运行中
    返回
    是否还有工作线程
    结束线程池
  • final void runWorker(Worker w)

    1. 循环执行firstTask或从阻塞队列中获取到任务
    2. 为worker加锁
    3. 若线程池为STOP,则中止线程
    4. 执行beforeExecute
    5. 执行run方法
    6. 执行afterExecute方法
    7. 为worker释放锁
  • private Runnable getTask()

    返回任务或返回null

    返回null的情况

    1. 多于maximumPoolSize的worker正在运行(执行了setMaximumPoolSize方法)
    2. 线程池状态>=STOP或线程池状态>=SHUTDOWN并阻塞队列为空
    3. 工作线程等待任务超时
    开始
    返回任务结束
    返回null结束
    1.工作线程>最大线程池数量

    线程可以被停止且已经超时
    2.有工作线程或阻塞队列为空
    线程是否可以超时
    workQueue.poll
    workQueue.take
    获取到任务
    返回任务结束
Worker
名字备注
thread从线程工厂获得的线程
firstTask首先要执行的任务,可以为空
completedTasks已完成的任务
  • Worker(Runnable firstTask)

    1. 设置firstTask
    2. 将run方法传入线程工厂获取新线程
  • public void run()

    执行runworker方法

  • public void lock()

    给worker加锁

  • public boolean tryLock()

    尝试给worker加锁

  • public void unlock()

    给worker解锁

  • public boolean isLocked()

    待定

多线程中的常量

源码

private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
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;
private static final int TERMINATED =  3 << COUNT_BITS;

private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

常量结果
常量结果

Github博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值