讲实话以前没有写过多线程编程,这次也是参考了网上其他的案例总结了一下,并且投身到京东那边的实际项目里尝试了一下,下面说一下实际案例。
SpringBoot内其实多线程一般还是走线程池,因为线程池好控制,内部也有一定控制,拒绝策略等等,还可以最大程度发挥线程的特性,发挥cpu的性能。
先说一下,我们在线程池Executor这边的配置类
这都是基本的配置类,网上随便就能抄到的。
@Configuration
@EnableAsync
public class ExecutorConfig {
private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
@Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(5);
//配置队列大小
executor.setQueueCapacity(99999);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
一般情况下我们在学多线程的时候,都是Thread的匿名内部类写法和Runnable的重写run方法,但是在springboot中,为我们直接定义好了这相关操作,只需要annotation就可以了。
要知道,我们实际上去使用了多线程,达到的还是一种异步的操作,所以不多说了,上代码。
常规定义一个接口:
常规的去实现,在这里网上资料都会告诉你在Service层,接口的实现方法上扔一个@Async(< beanname >)
像这样:
因为是公司代码,就不多展示了,意思就是这个意思。@Async上参数写一个刚才配置类里面定义线程池参数的方法名。
然后控制层再引用一下跑,一般网上csdn的博客都这么说,日志还打印的不错,实际上postman一测试,啥东西也没有,就这样的:
没错,其实的确是执行了多线程,看了网上资料的话,也能感受到,但是异步执行的时候,这种方法,也就是Thread和Runnable多线程开发的这种方法,是没办法获取返回值的。
背了面试题的各位应该知道Callable接口可以返回线程中的返回值,我梳理一下它们之间的关系。
Runnable和Callable都可以进行多线程开发,Executor接口创建的线程池,是调度他们俩的容器,如果我们想要具体的获取值,是可以通过Future来实现的,但是,区别就在于Runnable使用了Future还是不能得到返回值,而Callable是可以的。
这里可以去看一下FutureTask的源码,里面是有Callable的,这里就不展开了。
言归正传,我们要是想获取返回值,就要通过Future来实现。
也就是说,我们最后返回一个Future对象给控制层,然后控制层这样:
就可以得到返回值了。