@async 默认线程池_不仅会用@Async,我把源码也梳理了一遍(上)

5c9a1d7a831bee084284f3996335d8b3.png

说起异步化,很多人会想起异步线程、消息队列等,消息队列不是文章的主题,今天我们来聊聊spring对异步化的支持@EnableAsync&@Async。

我会分为以下几个步骤去说明,首先说说用法,然后再从源码层分析@Async的底层原理,同学们准备好了吗?

@Async用法

想要开启异步化,我们就必须要用用到@EnableAsync注解,这又是我们之前给大家说个的@EnableXXX的模块,大家可以回顾一下:《导图梳理springboot手动、自动装配,让springboot不再难懂》,配置类中开启了@EnableAsync之后,@Async的注解就开始起作用了,我们先来做个简单的测试:

配置类

  • com.example.demo.config.AsyncConfig

@EnableAsync

@Configuration

public class AsyncConfig {

}

一个页面控制器

  • com.example.demo.controller.AsyncController

@Slf4j

@RestController

public class AsyncController {

@Autowired

UserService userService;

@GetMapping("/tt")

public Object tt() throws InterruptedException {

String username = userService.findUserNameById(1L);

log.info("AsyncController----------->" + Thread.currentThread().getName());

log.info("username---------------->" + username);

return username;

}

}

然后就是业务类

  • com.example.demo.service.impl.UserServiceImpl

@Slf4j

@Service

public class UserServiceImpl implements UserService {

@Async

public String findUserNameById(Long id) {

log.info("UserServiceImpl----------->" + Thread.currentThread().getName());

return "关注公众号:java思维导图";

}

}

好了,最简单的用法已经完成了,我在UserServiceImpl#findUserNameById方法上添加了@Async注解,表示此方法是个异步方法。我们先来看看执行结果,然后再来说说上面的程序有什么问题。

控制台输出: 

6d145fb2889ee327b36c4b9558351c77.png 

可以看出,两个方法执行的线程是不一样的,明显UserServiceImpl的findUserNameById方法是另起了一个线程task-1执行。

这里我们注意到了一个问题,controller中我们获取不到了异步方法的返回值username了。所以想要获取@Async注解之后的异步方法就不能使用这种方式了,所以我们改下程序:

service中新添加个方法:

@Async

public Future<String> findLastNameById(Long id) {

log.info("UserServiceImpl----------->" + Thread.currentThread().getName());

return new AsyncResult<String>("关注公众号:java思维导图");

}

然后controller改成这样:

@GetMapping("/tt")

public Object tt() throws InterruptedException, ExecutionException {

String username = userService.findUserNameById(1L);

log.info("AsyncController----------->" + Thread.currentThread().getName());

log.info("username---------------->" + username);

Future<String> future = userService.findLastNameById(1L);

String lastname = future.get();

log.info("lastname---------------->" + lastname + Thread.currentThread().getName());

return username;

}

测试结果如下: 

78d9a9847e8970b1546571e76a63db9d.png

 可以看到task-1获取不到结果,task-2获取到结果了,但是这里有个问题,为了获取异步的结果,线程http-nio-8080-exec-1一直在等待future.get()的返回结果,才继续往下走,这就有点影响主线程的性能了。

那如果异步方法出现了异常,我们怎么去捕捉呢,一般全局异常处理我们都是处理controller中的异常,但这个异步线程的异常能不能捕捉到都是个问题。其实,对于@Async的异常,是可以配置的。AsyncConfig中我们可以继承一个AsyncConfigurer,然后重写两个方法:

  • com.example.demo.config.AsyncConfig

@EnableAsync

@Configuration

public class AsyncConfig implements AsyncConfigurer {

@Override

public Executor getAsyncExecutor() {

//线程池

ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();

taskExecutor.setCorePoolSize(5);

taskExecutor.setMaxPoolSize(10);

taskExecutor.setQueueCapacity(25);

taskExecutor.initialize();

return taskExecutor;

}

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

return new SimpleAsyncUncaughtExceptionHandler();

}

}

一个定义线程池,一个定义异常处理器,线程池我们就不说了,这个默认的SimpleAsyncUncaughtExceptionHandler没啥东西:

public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {

private static final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class);

@Override

public void handleUncaughtException(Throwable ex, Method method, Object... params) {

if (logger.isErrorEnabled()) {

logger.error("Unexpected exception occurred invoking async method: " + method, ex);

}

}

}

所以如果我们想自己处理这个出现异常之后的逻辑,还得重写AsyncUncaughtExceptionHandler 的handleUncaughtException接口,里面有method、params等参数,可以进行重试、或者其他处理等。

异步化原理

好吧,下一篇再写了,今天先到这里,下午还有点事~

待续~

结束语

坚持原创的第三篇(20190920),打卡打卡。希望你们会喜欢。

我是吕一明,欢迎关注我的公众号:java思维导图

做个小调查:

留言区留言:你们公司是用什么方式实现异步处理业务的?

- 精选文章 -

 导图梳理springboot手动、自动装配,让springboot不再难懂

 Springboot异常处理只会@ControllerAdvice+@ExceptionHandler?还远远不够!

堪称神器的 Chrome 插件

60天,他学了20个主流的框架、中间件,解读了5个开源项目

144c8998ac44677d849e6db7099996d0.png

(java思维导图)

长按关注,每天java一下,成就架构师

我就知道你在看!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值