【J.U.C】线程池之工作流程与ThreeadPoolExecutor介绍

文章首发于:clawhub.club


线程池工作流程

【J.U.C】线程池之工作流程与ThreeadPoolExecutor介绍_第1张图片
线程池的主要工作流程.png
  1. 如果当前运行的线程少于corePoolSize,则创建新线程(核心线程)来执行任务。
  2. 如果运行的线程等于或多于corePoolSize ,则将任务加入BlockingQueue。
  3. 如果BlockingQueue队列已满,则创建新的线程(非核心)来处理任务。
  4. 如果核心线程与非核心线程总数超出maxiumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

ThreeadPoolExecutor

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize
    除非设置了{@code allowCoreThreadTimeOut},否则要保留在池中的线程数,即使它们是空闲的。
  • maximumPoolSize
    池中允许的最大线程数。
  • keepAliveTime
    当线程数大于内核时,这是多余的空闲线程在终止新任务之前等待新任务的最长时间。
  • unit
    {@code keepAliveTime}参数的时间单位。
  • workQueue
    用于在任务执行前保存任务的队列。这个队列只包含{@code execute}方法提交的{@code Runnable}任务。
  • threadFactory
    执行程序创建新线程时使用的工厂。
  • handler
    由于达到线程边界和队列容量而阻塞执行时使用的处理程序。

BlockingQueue

  • SynchronousQueue
    不存储元素的阻塞队列,一个插入操作,必须等待移除操作结束,每个任务一个线程。
    使用的时候maximumPoolSize一般指定成Integer.MAX_VALUE。
  • LinkedBlockingQueue
    如果当前线程数大于等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中。
  • ArrayBlockingQueue
    可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误。
  • DelayQueue
    队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务。
  • priorityBlockingQuene
    具有优先级的无界阻塞队列。

RejectedExecutionHandler

有4个ThreeadPoolExecutor内部类。

  • AbortPolicy
    直接抛出异常,默认策略。
  • CallerRunsPolicy
    用调用者所在的线程来执行任务。
  • DiscardOldestPolicy
    丢弃阻塞队列中靠最前的任务,并执行当前任务。
    4、DiscardPolicy
    直接丢弃任务。

最好自定义饱和策略,实现RejectedExecutionHandler接口,如:记录日志或持久化存储不能处理的任务。

线程池大小设置

  • CPU密集型
    尽量使用较小的线程池,减少CUP上下文切换,一般为CPU核心数+1。
  • IO密集型
    可以适当加大线程池数量,IO多,所以在等待IO的时候,充分利用CPU,一般为CPU核心数2倍。
    但是对于一些特别耗时的IO操作,盲目的用线程池可能也不是很好,通过异步+单线程轮询,上层再配合上一个固定的线程池,效果可能更好,参考Reactor模型,后期总结。
  • 混合型
    视具体情况而定。

任务提交

  • Callable
    通过submit函数提交,返回Future对象。
  • Runnable
    通过execute提交,没有返回结果。

关闭线程池

  • shutdown()
    仅停止阻塞队列中等待的线程,那些正在执行的线程就会让他们执行结束。
  • shutdownNow()
    不仅会停止阻塞队列中的线程,而且会停止正在执行的线程。

你可能感兴趣的:(【J.U.C】线程池之工作流程与ThreeadPoolExecutor介绍)