概念

构建了一个生产者消费者模型,将线程和任务解耦,并不直接关联,复用线程。

线程池的状态

image.png

主要参数

  • 核心线程数
  • 最大线程数
  • 存活时间
  • 存活时间的单位
  • 阻塞队列
  • 拒绝策略

工作流程

image.png

常见的线程池

newFixedThreadPool

  1. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
  2. return new ThreadPoolExecutor(nThreads, nThreads,
  3. 0L, TimeUnit.MILLISECONDS,
  4. new LinkedBlockingQueue<Runnable>(),
  5. threadFactory);
  6. }

阻塞队列为无界队列,队列容量为 Integer.MAX_VALUE。

newSingleThreadExecutor

  1. public static ExecutorService newSingleThreadExecutor() {
  2. return new FinalizableDelegatedExecutorService
  3. (new ThreadPoolExecutor(1, 1,
  4. 0L, TimeUnit.MILLISECONDS,
  5. new LinkedBlockingQueue<Runnable>()));
  6. }

阻塞队列为无界队列,大量请求可能导致堆积请求,而耗费非常大的内存。

newCachedThreadPool

  1. public static ExecutorService newCachedThreadPool() {
  2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3. 60L, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>());
  5. }

会导致线程数量可能一直增加。

newScheduledThreadPool

  1. public ScheduledThreadPoolExecutor(int corePoolSize,
  2. ThreadFactory threadFactory) {
  3. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
  4. new DelayedWorkQueue(), threadFactory);
  5. }
  • newFixedThreadPool和newSingleThreadExecutor:   主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
  • newCachedThreadPool和newScheduledThreadPool:   主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

    阻塞队列的使用场景

    参考
    image.png
    ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
    LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。(默认长度为Integer.MAX_VALUE)
    PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
    DelayQueue:一个使用优先级队列实现的无界阻塞队列。
    SynchronousQueue:一个不存储元素的阻塞队列。
    LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
    LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

    ArrayBlockingQueue

    基于数组、读写共用一把锁(RenentrantLock),无法真正意义上进行读写并行。
    适用于项目中,并发量不高的地方。
    固定容量,如果容量太小,取数据比存数据慢,会阻塞大量线程

LinkedBlockingQueue (推荐)

基于链表,默认整数最大值容量。
读写锁分离,适合高并发场景。
如果取数据过慢,可能导致大量任务堆积,导致内存被消耗。

PriorityBlockingQueue

支持任务排序,用在分级消费的场景:例如VIP用户优先处理。

DelayQueue

延迟队列,基于优先级队列实现。比较的是时间。
场景: 订单超时取消功能
用户下订单未支付开始倒计时,超时则释放订单中的资源,如果取消或者完成支付,我们再讲队列中的数据移除掉。

SynchronousQueue

采用双栈双队列算法的无空间队列或栈 任何一个对SynchronousQueue写需要等到一个对SynchronousQueue的读操作,任何一个个读操作需要等待一个写操作 没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者。
分析: 相当于是交换通道,不存储任何元素,提供者和消费者是需要组队完成工作,缺少一个将会阻塞线程,直到等到配对为止
场景:newCachedThreadPool,轻量级别任务转交。
这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程默认空闲了60秒后会被回收

拒绝策略

image.png

线程池参数配置

尽量使用有界阻塞队列。

  • CPU密集型:尽可能少的线程,Ncpu+1
  • IO密集型:尽可能多的线程,Ncpu * 2。(例如数据库连接池)

    参考资料

    链接