遇到的@Async注解的一些问题
1.在使用@Async的时候,如果异步方法出现异常,调用者无法感知。
@Service
public class AsyncService {
@Async("asyncServiceExecutorSingle")
public void asyncTest01(){
System.out.println("Async Run ...."+Thread.currentThread().getName());
int i = 1/0;
}
}
配置类
@Configuration
public class AsyncConfiguration{
private static final Logger logger = LoggerFactory.getLogger(AsyncException.class);
@Bean
public Executor asyncServiceExecutorSingle() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(1);
//配置最大线程数
executor.setMaxPoolSize(1);
//配置队列大小
executor.setQueueCapacity(1);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-one-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class AsyncTest {
@Autowired
private AsyncService asyncService;
@Test
public void test01() {
try {
asyncService.asyncTest01();
// System.in.read();
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
System.out.println(e.getMessage() + "捉住了~");
}
}
}
结果
说明异常并没有被调用者感知,使得处理异常很麻烦。如果异常确实需要我们去手动处理,那么有没有更好的处理办法呢?
通过AsyncConfigurer异常处理 (也可自定义线程池)如下:
修改配置类,实现AsyncConfig接口
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
private static final Logger logger = LoggerFactory.getLogger(AsyncConfiguration.class);
@Bean
public Executor asyncServiceExecutorSingle() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(1);
//配置最大线程数
executor.setMaxPoolSize(1);
//配置队列大小
executor.setQueueCapacity(1);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-one-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler{
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
// System.out.println(throwable.getMessage()+method.getName());
logger.error(method.getName(),throwable.getMessage());
}
}
}
控制台输出结果
Async Run ....async-one-service-1
2021-06-17 16:25:30.706 ERROR 8708 --- [c-one-service-1] com.halon.AsyncConfiguration : asyncTest01
2. 调用自己类上的异步方法不起作用
这是官方文档上的第二条注意点
原因:与Spring的生命周期或者说是初始化有关系,如果添加了@Async注解Spring会生成一个代理对象,在执行该方法的时候需要异步执行,就不会调用原本被代理类的该方法。在内部会有一个队列,Spring会把异步方法放入队列里等待线程池去读取去执行方法,从而达到异步的目的。
所以在同一个类中,调用自己类上的异步方法是没有作用的!!!!
类似的:@Transactional注解也是一样的!!!