0%

线程池

线程池.png

概念

管理一组线程的对象

作用

线程的创建和销毁需要消耗相当的资源,利用线程池可以提高创建线程的速度,并且线程可以被重复利用

创建

ThreadPoolExecutor

  • 参数

    • int corePoolSize

      • 核心线程数量
    • int maximumPoolSize

      • 线程池的最大线程数(核心线程+非核心线程)
    • long keepAliveTime

      • 非核心线程的存活时间
    • TimeUnit unit

    • BlockingQueue workQueue

      • 存放任务的阻塞队列
    • ThreadFactory threadFactory

    • RejectedExecutionHandler handler

      • 线程池饱和如何处理

执行

流程

  • 核心线程

    • 阻塞队列

      • 线程池

        • Handler

拒绝策略

线程池满了之后,再提交任务如何处理的问题

  • Abort(直接抛异常)
  • Discard(忽略新提交的任务)
  • DiscardOldest(移除阻塞队列最旧的)
  • CallerRun(交给线程池调用者处理)

异常处理

线程池内发生异常悄无声息,可能无法感知,需要主动去处理

  • 直接在任务内部try+catch
  • 用try+catch包裹future.submit
  • 为工作线程设置UncaughtExceptionHandler
  • 覆写线程池的AfterExcute方法

线程池的工作队列

阻塞队列,类似经典的IPC问题:生产-消费者问题,一个线程消耗,一个线程生产,在适当的时候需要阻塞线程

ArrayBlockingQueue

  • 用数组实现
  • FIFO
  • 容量无法改变

LinkedBlockingQueue

  • 用链表实现
  • 可设置大小,默认Integer.MAX_VALUE
  • FixedThreadPool采用这种阻塞队列

DelayQueue

  • 根据指定的时间(1st)和进入队列的时间(2nd)排序
  • ScheduledThreadPool采用这种阻塞队列

PriorityBlockingQueue

SynchronousQueue

  • 内部只能包含一个元素,插入元素的线程被阻塞,直到另一个线程获取了队列中的元素,反之亦然
  • CachedThreadPool采用这种阻塞队列

常用线程池

FixedThreadPool

  • 特点

    • 核心线程数和最大线程数相等

    • keepAliveTime=0

    • 使用LinkedBlockingQueue(无界)

      使用无界队列可能会使内存占用飙升,最终OOM

  • 流程

    • 核心线程–>阻塞队列–>OOM
  • 使用场景

    • 适合执行长期的,CPU密集型任务

CachedThreadPool

  • 特点

    • 核心线程数为0,最大线程数Integer.MAX_VALUE

      都是打工仔,没有一个有编制

    • 使用SynchronousQueue

    • 非核心线程存活时间60s

  • 流程

    • 阻塞队列–>非核心线程–>非核心线程的销毁
  • 使用场景

    • 并发执行大量短期的小任务

SingleThreadExecutor

  • 特点

    • 只有一个核心线程
    • 使用LinkedBlockingQueue(无界)
  • 流程

    • 一个线程日以继夜,笔耕不辍
  • 使用场景

    • 串行执行的任务

ScheduledThreadPool

  • 特点

    • 使用DelayQueue作为阻塞队列
    • 没有非核心线程
    • 可以设置周期和延迟
  • 流程

    • DelayQueue–>核心线程–>DelayQueue
  • 使用场景

    • 周期性的任务