我们在实际项目中有些复杂运算、耗时操作,就可以利用多线程来充分利用CPU,提高系统吞吐量。SpringBoot对多线程支持非常好,对我们的开发非常便捷。
在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync。调用也简单,在由Spring管理的对象的方法上标注注解@Async,显式调用即可生效。一般使用Spring提供的ThreadPoolTaskExecutor类。
需要的注解
springboot 配置多线程需要两个注解
-
@EnableAsync
在配置类中通过加@EnableAsync开启对异步任务的支持
-
@Async
在需要执行的方法上加@Async表明该方法是个异步方法,如果加在类级别上,则表明类所有的方法都是异步方法
配置代码
@Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer {
@Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(10); taskExecutor.setQueueCapacity(20); taskExecutor.setKeepAliveSeconds(60); taskExecutor.setThreadNamePrefix("hello-"); taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.initialize(); return taskExecutor; } }
|
Service
这里的方法自动被注入使用上文配置的ThreadPoolTaskExecutor
@Service public class AsyncService { @Async public void executeAsync1() { try { Thread.sleep(20); LoggerFactory.getLogger(AsyncService.class).info("异步任务::1"); } catch (InterruptedException e) { e.printStackTrace(); } }
@Async public void executeAsync2() { LoggerFactory.getLogger(AsyncService.class).info("异步任务::2"); } }
|
进阶:带返回值的异步任务
有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:
@Service public class AsyncService { @Async public void executeAsync1() { try { Thread.sleep(20); LoggerFactory.getLogger(AsyncService.class).info("异步任务::1"); } catch (InterruptedException e) { e.printStackTrace(); } }
@Async public void executeAsync2() { LoggerFactory.getLogger(AsyncService.class).info("异步任务::2"); }
@Async public ListenableFuture<String> sayHello(String name) { String res = name + ":Hello World!"; LoggerFactory.getLogger(AsyncService.class).info(res); return new AsyncResult<>(res); }
}
|
调用
@SpringBootApplication public class TaskExecutorApplication implements CommandLineRunner { @Autowired private ApplicationContext context;
public static void main(String[] args) { SpringApplication.run( TaskExecutorApplication.class, args ); }
@Override public void run(String... strings){ AsyncService asyncService = context.getBean(AsyncService.class); try { for (int i = 0; i < 10; i++) { asyncService.executeAsync1(); asyncService.executeAsync2(); } Thread.sleep(1000); asyncService.sayHello("yan").get(); asyncService.sayHello("yan").get(1, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { e.printStackTrace(); } }
}
|