问题现象
在我们的系统中,使用了这样的配置来开启异步操作:<task:annotation-driven executor="executor" scheduler="scheduler" /><task:executor id="executor" pool-size="16-128" keep-alive="60" rejection-policy="CALLER_RUNS" queue-capacity="1000" />
客户端开启异步代码如下:
@Async()public Future calculateByLendId(int lendrequestId) {
// 标记1 // 调用REST服务;监控调用时间。 } // 获取Future后的处理如下try {
keplerOverdue = summay4Overdue.get(5, TimeUnit.SECONDS); // 后续处理} catch (Exception e) {
// 标记2 // 异常报警 }
然而在这种配置下,客户端在标记1处监控到的调用时间普遍在4s以内(平均时间不到1s,个别峰值请求会突破5s ,全天超过5s的请求不到10个。然而,在标记2处捕获到的超时异常却非常多,一天接近700+ 。 问题出在哪儿?
原因分析
上述问题相关代码的调用时序如下图所示。任务调度逻辑
使用注解得到的bean是ThreadPoolTaskExecutor的实例。这个类本身并不做调度,而是将调度工作委托给了ThreadPoolExecutor。后者的任务调度代码如下:/** * Executes the given task sometime in the future. The task * may execute in a new thread or in an existing pooled thread. * * If the task cannot be submitted for execution, either because this * executor has been shutdown or because its capacity has been reached, * the task is handled by the current {
@code RejectedExecutionHandler}. * * @param command the task to execute * @throws RejectedExecutionException at discretion of * {
@code RejectedExecutionHandler}, if the task * cannot be accepted for execution * @throws NullPointerException if {
@code command} is null */public void execute(Runnable command) {
if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-ch