5

java | ThreadPoolExecutor 用法

 1 year ago
source link: https://benpaodewoniu.github.io/2023/01/01/java156/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

156_0.png

线程池状态

ThreadPoolExecutor 使用 int 的高 3 位来表示线程池的状态,低 29 为表示线程池数量。「之所以以一个 int 来记录两个信息,而不是用两个 int 记录,是因为,使用一个 int 可以用 cas 原子操作进行赋值」

状态名 高3位 接收新任务 处理阻塞队列任务 说明
RUNNING 111 Y Y
SHUTDOWN 000 N Y 不会接收新任务,但会处理阻塞队列剩余任务
STOP 001 N N 会终端正在执行的任务,并抛弃阻塞队列的任务
TIDYING 010 - - 任务全部执行完毕,活动线程为 0 即将进入终结
TERMINATED 011 - - 终结状态
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
  • corePoolSize
    • 核心线程数目「最多保留的线程数」
  • maximumPoolSize
    • 最大线程数目
      • 救急线程数等于 = maximumPoolSize - corePoolSize
      • 救急线程可以执行突发任务,比如任务队列选择有界队列,任务的数量超过了队列大小,就会创建 maximumPoolSize - corePoolSize 数目的救急线程来救急
  • keepAliveTime
    • 生存时间 - 针对救急线程
  • unit
    • 时间单位 - 针对救急线程
  • workQueue
  • threadFactory
    • 线程工厂 - 可以为线程创建时起个好名字
  • handler

关于上述的用法可以参考 自定义阻塞队列

如果线程达到 maximumPoolSize 任有新任务,则会执行拒绝策略,拒绝策略由 JDK 提供了 4 种实现

  • AbortPolicy
    • 让调用者抛出 RejectedExecutionException 异常,这是默认策略
  • CallerRunsPolicy
    • 让调用者运行任务
  • DiscardPolicy
    • 放弃本次任务
  • DiscardOldestPolicy
    • 放弃队列中最早的任务,本任务取而代之

除此之外,其他框架的实现如下

  • Dubbo
    • 在抛出 RejectedExecutionException 异常前会记录日志,并 dump 线程栈信息,方便定位问题
  • Netty
    • 创建一个新的线程执行任务
  • ActiveMQ
    • 带超时等待(60s)尝试放入队列
  • PinPoint
    • 使用了拒绝策略链,会逐一尝试策略链中每种拒绝策略

当高峰过去后,超过 corePoolSize 的救急线程,如果有一段时间没有任务做,需要结束节省资源,这个时间由 keepAliveTimeunit 控制。

根据这个构造方法,JDK Executors 类中提供了众多工厂方法来创建各种用途的线程池。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK