异步的概念和定义、请自行查阅,本文不再赘述。下面主要讲解异步的使用方法,和异步使用中需要注意的地方。
如何使用异步
以下是一个JAVA SpringBoot应用,使用@Async注解(该注解由spring提供)实现异步方法的具体过程。
1、首先创建线程池,这里需要注意的是,在项目的启动类上也需要添加@EnableAsync,
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
/** 核心线程数(默认线程数) */
private static final int corePoolSize = 20;
/** 最大线程数 */
private static final int maxPoolSize = 100;
/** 允许线程空闲时间(单位:默认为秒) */
private static final int keepAliveTime = 10;
/** 缓冲队列大小 */
private static final int queueCapacity = 200;
/** 线程池名前缀 */
private static final String threadNamePrefix = "Async-Service-";
@Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
2、在需要被异步执行的方法上添加 @Async 注解,
@Service
public class TranTest2Service {
Logger log = LoggerFactory.getLogger(TranTest2Service.class);
// 发送提醒短信 1
@Async("taskExecutor")
public void sendMessage1() throws InterruptedException {
log.info("发送短信方法---- 1 执行开始");
// 模拟耗时
Thread.sleep(3000);
log.info("发送短信方法---- 1 执行结束");
}
// 发送提醒短信 2
@Async("taskExecutor")
public void sendMessage2() throws InterruptedException {
log.info("发送短信方法---- 2 执行开始");
Thread.sleep(2000);
log.info("发送短信方法---- 2 执行结束");
}
@Async("taskExecutor")
public Future<String> sendMessage3(Integer num) throws InterruptedException {
log.info("发送短信方法---- 3 执行开始" + num);
Thread.sleep(new Random().nextInt(10000) + 1000);
log.info("发送短信方法---- 3 执行结束" + num);
return new AsyncResult("sendMessage3 : I am method");
}
}
3、在另外一个类中调用上述异步方法。
@Service
public class OrderTaskServic {
@Resource
private TranTest2Service tranTest2Service;
// 订单处理任务
public void orderTask() throws InterruptedException, ExecutionException {
tranTest2Service.sendMessage1(); // 发短信的方法 1
tranTest2Service.sendMessage2(); // 发短信的方法 2
this.cancelOrder(); // 取消订单
List<Future<String>> futureList = new CopyOnWriteArrayList<>();
for (int i = 0; i < 20; i++) {
Future<String> result = tranTest2Service.sendMessage3(i);
futureList.add(result);
}
while (true) {
int acount = 0;
int size = futureList.size();
for (Future<String> result : futureList) {
if (result.isDone()) {
acount++;
System.out.println(result.get());
futureList.remove(result);
}
}
if (acount == size) {
break;
}
Thread.sleep(1000);
}
}
// 取消订单
public void cancelOrder() throws InterruptedException {
System.out.println("取消订单的方法执行------开始");
System.out.println("取消订单的方法执行------结束 ");
}
}
4、测试一下
@SpringBootTest
@EnableAsync
class DemoApplicationTests {
@Resource
private OrderTaskServic orderTaskServic;
@Test
void contextLoads() {
System.out.println("XXXXXXXX");
try {
orderTaskServic.orderTask();
} catch (Exception e) {
System.out.println(e);
}
}
}
另外如果需要拿到异步方法的执行结果,可以使用Future<>结合Future.isDone来实现。