自己动手实现线程池 jdk线程池ThreadPoolExecutor工作原理解析(一)( 九 )

目前为止,通过v1版本的MyThreadPoolExecutor源码,已经将jdk线程池ThreadPoolExecutor在RUNNING状态下提交任务 , 启动工作线程执行任务相关的核心逻辑讲解完毕了(不考虑优雅停止) 。
jdk线程池默认支持的四种拒绝策略jdk线程池支持用户传入自定义的拒绝策略处理器,只需要传入实现了RejectedExecutionHandler接口的对象就行 。而jdk在ThreadPoolExecutor中提供了默认的四种拒绝策略方便用户使用 。

  1. AbortPolicy拒绝接受任务时会抛出RejectedExecutionException,能让提交任务的一方感知到异常的策略 。适用于大多数场景 , 也是jdk默认的拒绝策略 。
  2. DiscardPolicy直接丢弃任务的拒绝策略 。简单的直接丢弃任务,适用于对任务执行成功率要求不高的场合
  3. DiscardOldestPolicy丢弃当前工作队列中最早入队的任务,然后将当前任务重新提交 。适用于后出现的任务能够完全代替之前任务的场合(追求最终一致性)
  4. CallerRunsPolicy令调用者线程自己执行所提交任务的拒绝策略 。在线程池压力过大时,让提交任务的线程自己执行该任务(异步变同步),能有效地降低线程池的压力 , 也不会丢失任务,但可能导致整体业务吞吐量大幅降低 。
上面介绍的四种jdk默认拒绝策略分别适应不同的业务场景,需要用户仔细考虑最适合的拒绝策略 。同时灵活的、基于接口的设计也开放的支持用户去自己实现更贴合自己业务的拒绝策略处理器 。
/*** 默认的拒绝策略:AbortPolicy* */private static final MyRejectedExecutionHandler defaultHandler = new MyAbortPolicy();/*** 抛出RejectedExecutionException的拒绝策略* 评价:能让提交任务的一方感知到异常的策略,比较通用,也是jdk默认的拒绝策略* */public static class MyAbortPolicy implements MyRejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable command, MyThreadPoolExecutor executor) {// 直接抛出异常throw new RejectedExecutionException("Task " + command.toString() +" rejected from " + executor.toString());}}/*** 令调用者线程自己执行command任务的拒绝策略* 评价:在线程池压力过大时 , 让提交任务的线程自己执行该任务(异步变同步),*能够有效地降低线程池的压力,也不会丢失任务,但可能导致整体业务吞吐量大幅降低* */public static class MyCallerRunsPolicy implements MyRejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable command, MyThreadPoolExecutor executor) {if (!executor.isShutdown()) {// 如果当前线程池不是shutdown状态,则令调用者线程自己执行command任务command.run();}else{// 如果已经是shutdown状态了,就什么也不做直接丢弃任务}}}/*** 直接丢弃任务的拒绝策略* 评价:简单的直接丢弃任务,适用于对任务执行成功率要求不高的场合* */public static class MyDiscardPolicy implements MyRejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable command, MyThreadPoolExecutor executor) {// 什么也不做的,直接返回// 效果就是command任务被无声无息的丢弃了,没有异常}}/*** 丢弃当前工作队列中最早入队的任务,然后将当前任务重新提交* 评价:适用于后出现的任务能够完全代替之前任务的场合(追求最终一致性)* */public static class MyDiscardOldestPolicy implements MyRejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable command, MyThreadPoolExecutor executor) {if (!executor.isShutdown()) {// 如果当前线程池不是shutdown状态,则丢弃当前工作队列中最早入队的任务,然后将当前任务重新提交executor.getQueue().poll();executor.execute(command);}else{// 如果已经是shutdown状态了,就什么也不做直接丢弃任务}}}jdk默认的四种线程池实现jdk中除了提供了默认的拒绝策略 , 还在Executors类中提供了四种基于ThreadPoolExecutor的、比较常用的线程池,以简化用户对线程池的使用 。这四种线程池可以通过Executors提供的public方法来分别创建:
newFixedThreadPoolnewFixedThreadPool方法创建一个工作线程数量固定的线程池,其创建ThreadPoolExecutor时传入的核心线程数corePoolSize和最大线程数maximumPoolSize是相等的 。因此其工作队列传入是一个无界的LinkedBlockingQueue,无界的工作队列意味着永远都不会创建新的非核心线程 。在默认allowCoreThreadTimeOut为false的情况下,线程池中的所有线程都是不会因为idle超时而销毁的核心线程 。适用场景:由于工作线程数量固定,“fixedThreadPool”适用于任务流量较为稳定的场景
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}

推荐阅读