线程池自带的那些拒绝策略
今天被边上的小伙伴问到如果线程池处理不过来,但是队列又是个有界队列的时候该怎么办,害得我又翻了半天书重看了下线程池的相关内容。哎,有些东西一段时间不用之后就有可能忘了,所以趁这个机会来深入了解下JDK1.8线程池的拒绝策略,其实也蛮简单的。
线程池的拒绝策略有如下四种:
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常 (默认)
DiscardPolicy:也是丢弃任务,但是不抛出异常
DiscardOldestPolicy:丢弃队列最前面的任务,执行后面的任务
CallerRunsPolicy:由调用线程处理该任务
拒绝策略在线程池执行任务的execute()方法中用到,有两处地方:
- 线程池此时不处于running状态,调用拒绝策略拒绝任务
- 线程池创建新的Worker失败,调用拒绝策略拒绝任务
这些拒绝策略都实现了RejectedExecutionHandler接口,该接口只有一个方法:
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
注意这个接口返回的是void
下面来逐个看下这些拒绝策略的源码:
AbortPolicy:
源码中就直接throw了一个异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }
DiscardPolicy:
...更简单,方法里面是个空,即抛弃掉任务并且什么都不做
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { }
DiscardOldestPolicy
也很简单,如果线程池没有shutdown,那么就讲队列中的任务poll出来一个(对于这个任务什么也不做,就是丢弃掉了最早的任务);然后在调用execute()方法执行刚提交的任务(扔到队列里面)。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } }
CallerRunsPolicy
最流弊的是这个...让提交任务的线程自己来执行(前提是线程池没有shutdown)。哈哈,看到这个策略,发现自己好像又学到了一点。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run();//让提交任务的线程自己run,hhh } }