Java线程池ThreadPoolExecutor的4种拒绝策略

2017-05-21 05:53:11 +0000

最近在做大批量数据采集转换工作,基础数据在本地但是需要调用网络资源完成数据转换。多方面原因在保证良好运行情况下,最多开5个线程进行网络资源调用。方案是基础数据在数据库分页,循环遍历每一条数据,创建调用任务并加入ThreadPoolExecutor线程池任务队列。

 

在印象中当加入的任务数量超过一定数目(maximumPoolSize + BlockingQueue 队列长度),默认情况下会抛出异常。这种情况会造成某些采集、转换错误、遗漏,肯定是不符合我的预期。期望的结果是,分页循环遍历基础数据,为每一条数据创建采集转换任务依次加入任务队列,当任务队列满主线程阻塞等待或者减缓创建和加入的速度。

 

解决这个问题的关键点在于怎么处理被拒绝的任务,只能去温习其拒绝策略,顺便回忆啃Thinking in Java的情景。

      

1. 策略1:ThreadPoolExecutor.AbortPolicy(),中止策略,将抛出 RejectedExecutionException。默认的情况下就是这种策略。

 

源码上的注释

In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.

 

 

2. 策略2:ThreadPoolExecutor.CallerRunsPolicy()

CallerRunsPolicy从字面意思是调用者执行策略。ThreadPoolExecutor.CallerRunsPolicy()拒绝任务的处理程序,它直接在调用ThreadPoolExecutor.execute方法的线程中运行被拒绝的任务,除非执行程序已经关闭,在这种情况下此任务被丢弃。这个策略有个好处是可以减缓新任务加入任务队列。

设置策略代码如下:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10));

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

 

 

附:官方文档解释

A handler for rejected tasks that runs the rejected task directly in the calling thread of the execute method, unless the executor has been shut down, in which case the task is discarded.

 

源码上的注释

In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.

 

 

3. 策略3:ThreadPoolExecutor.DiscardOldestPolicy()

丢弃最老的(加入队伍中时间最久)任务策略。先看下源码注释关于此策略的解释:

 

源码上的注释

In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)

如果线程池执行器没有关闭,在任务队列头的任务(理解队列的FIFO先进先出)会被丢弃,然后重试执行。(可能会再次失败,导致重复此策略)。

 

 

4. 策略4:ThreadPoolExecutor.DiscardPolicy

丢弃策略。无法执行的任务将被简单地删除,与策略1不同,不抛出异常。

 

源码上的注释

In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.

 

过一遍后,基本上策略3是满足我的需求。