线程池ThreadPoolExecutor,它的执行规则如下:
在Springboot中对其进行了简化处理,只需要配置一个类型为 java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync。
调用也简单,在由Spring管理的对象的方法上标注注解@Async,显式调用即可生效。
一般使用Spring提供的ThreadPoolTaskExecutor类。
@Configuration @EnableAsync public class BeanConfig { @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数 executor.setCorePoolSize(5); // 设置最大线程数 executor.setMaxPoolSize(10); // 设置队列容量 executor.setQueueCapacity(20); // 设置线程活跃时间(秒) executor.setKeepAliveSeconds(60); // 设置默认线程名称 executor.setThreadNamePrefix("hello-"); // 设置拒绝策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
测试调用:
@Component public class Hello { @Async public void sayHello(String name) { LoggerFactory.getLogger(Hello.class).info(name + ":Hello World!"); } }
执行结果:
进阶:
有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,
使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:
@Async public ListenableFuture<String> sayHello(String name) { String res = name + ":Hello World!"; LoggerFactory.getLogger(Hello.class).info(res); return new AsyncResult<>(res); }
调用返回值:
@Autowired private Hello hello; // 阻塞调用 hello.sayHello("yan").get(); // 限时调用 hello.sayHello("yan").get(1, TimeUnit.SECONDS)
扩充:
实际上,@Async还有一个参数,通过Bean名称来指定调用的线程池-比如上例中设置的线程池参数不满足业务需求,可以另外定义合适的线程池,
调用时指明使用这个线程池-缺省时springboot会优先使用名称为'taskExecutor'的线程池,如果没有找到,才会使用其他类型为TaskExecutor或其子类的线程池。