1 场景复现
服务调用时序如图1所示。中间件服务使用线程池ThreadPoolExecutor,配置丢弃策略为DiscardOldestPolicy(丢弃队列中等待最久的任务),队列容量为10。
public static ExecutorService threadPoolExecutorGenerate = new ThreadPoolExecutor(
ThreadPoolConstant.CORE_THREAD_NUM,
ThreadPoolConstant.MAX_THREAD_NUM,
ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(ThreadPoolConstant.QUEUE_LENGTH),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortOldestPolicy());
2 原因
线程池配置丢弃策略为DiscardOldestPolicy(丢弃队列中等待最久的任务),队列容量为10,当队列达到上限时,丢弃任务,此时,后台服务无法获取到中间件丢弃任务的返回值,导致后台服务异常。
3 方案
中间件服务具有特殊性,必须要有返回值以确定当前任务是否正常,因此,使用线程池时,应该使用拒绝策略AbortPolicy,当拒绝任务后,抛出异常,在程序中捕获异常,并返回默认值或约定的值,保证中间件服务不会卡住,后台服务可以及时拿到数据,保证后台服务不会卡住。
3.1 AbortPolicy拒绝策略实现
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
3.2 完整配置
public static ExecutorService threadPoolExecutorGenerate = new ThreadPoolExecutor(
ThreadPoolConstant.CORE_THREAD_NUM,
ThreadPoolConstant.MAX_THREAD_NUM,
ThreadPoolConstant.KEEP_ALIVE_TIME_SECONDS,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(ThreadPoolConstant.QUEUE_LENGTH),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
4 小结
线程池策略:
- 需要及时得到响应的服务,使用拒绝策略,捕获异常,及时返回默认值或约定值
- 有补偿机制或无序及时处理的,可以使用丢弃策略。