SpringBoot系列:Spring Boot异步挪用@Async
2019-11-18杂谈搜奇网74°c
A+ A-在现实开辟中,有时刻为了及时处置惩罚请乞降举行相应,我们能够会多使命同时实行,或许先处置惩罚主使命,也就是异步挪用,异步挪用的完成有许多,比方多线程、定时使命、音讯行列等,
这一章节,我们就来讲讲@Async异步要领挪用。
一、@Async运用演示
@Async是Spring内置注解,用来处置惩罚异步使命,在SpringBoot中一样实用,且在SpringBoot项目中,除了boot自身的starter外,不须要分外引入依靠。
而要运用@Async,须要在启动类上加上@EnableAsync主动声明来开启异步要领。
@EnableAsync
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
现假设有3个使命须要去处置惩罚,离别对应AsyncTask类的taskOne、taskTwo、taskThree要领,这里做了线程的sleep来模仿现实运转。
@Slf4j
@Component
public class AsyncTask {
private Random random = new Random();
public void taskOne() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命一实行完成耗时{}秒", (end - start)/1000f);
}
public void taskTwo() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命二实行完成耗时{}秒", (end - start)/1000f);
}
public void taskThree() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命三实行完成耗时{}秒", (end - start)/1000f);
}
}
然后编写测试类,由于@Async注解须要再Spring容器启动后才见效,所以这里讲测试类放到了SpringBoot的test包下,运用了SpringBootTest。
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootApplication.class)
public class AsyncTaskTest {
@Autowired
private AsyncTask asyncTask;
@Test
public void doAsyncTasks(){
try {
long start = System.currentTimeMillis();
asyncTask.taskOne();
asyncTask.taskTwo();
asyncTask.taskThree();
Thread.sleep(5000);
long end = System.currentTimeMillis();
log.info("主程序实行完成耗时{}秒", (end - start)/1000f);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运转测试要领,能够在控制台看到使命一二三按递次实行,末了主程序完成,这和我们的预期一样,由于我们没有任何分外的处置惩罚,他们就是一般的要领,按编码递次顺次实行。
而假如要使使命并发实行,我们只须要在使命要领上运用@Async注解即可,须要注重的是@Async所润饰的要领不要定义为static范例,如许异步挪用不会见效。
@Slf4j
@Component
public class AsyncTask {
private Random random = new Random();
//@Async所润饰的函数不要定义为static范例,如许异步挪用不会见效
@Async
public void taskOne() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命一实行完成耗时{}秒", (end - start)/1000f);
}
@Async
public void taskTwo() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命二实行完成耗时{}秒", (end - start)/1000f);
}
@Async
public void taskThree() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命三实行完成耗时{}秒", (end - start)/1000f);
}
}
然后我们在运转测试类,这个时刻输出能够就八门五花了,恣意使命都能够先实行完成,也有能够有的要领由于主程序封闭而没有输出。
二、Future猎取异步实行效果
上面演示了@Async,然则有时刻除了须要使命并发调度外,我们还须要猎取使命的返回值,且在多使命都实行完成后再终了主使命,这个时刻又该怎样处置惩罚呢?
在多线程里经由过程Callable和Future能够猎取返回值,这里也是相似的,我们运用Future返回要领的实行效果,AsyncResult 是Future的一个完成类。
@Slf4j
@Component
public class FutureTask {
private Random random = new Random();
//@Async所润饰的函数不要定义为static范例,如许异步挪用不会见效
@Async
public Future<String> taskOne() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命一实行完成耗时{}秒", (end - start)/1000f);
return new AsyncResult <>("使命一Ok");
}
@Async
public Future<String> taskTwo() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命二实行完成耗时{}秒", (end - start)/1000f);
return new AsyncResult <>("使命二OK");
}
@Async
public Future<String> taskThree() throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("使命三实行完成耗时{}秒", (end - start)/1000f);
return new AsyncResult <>("使命三Ok");
}
}
在AsyncResult中:
- isDone()要领能够用于推断异步要领是不是实行完成,若使命完成,则返回true
- get()要领可用于猎取使命实行后返回的效果
- cancel(boolean mayInterruptIfRunning)可用于作废使命,参数mayInterruptIfRunning示意是不是许可作废正在实行却没有实行终了的使命,假如设置true,则示意能够作废正在实行过程当中的使命
- isCancelled()要领示意使命是不是被作废胜利,假如在使命一般完成前被作废胜利,则返回 true
- get(long timeout, TimeUnit unit)用来猎取实行效果,假如在指定时间内,还没猎取到效果,就直接返回null
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootApplication.class)
public class AsyncTaskTest {
@Autowired
private FutureTask futureTask;
@Test
public void doFutureTasks(){
try {
long start = System.currentTimeMillis();
Future <String> future1 = futureTask.taskOne();
Future <String> future2 = futureTask.taskTwo();
Future <String> future3 = futureTask.taskThree();
//3个使命实行完成以后再实行主程序
do {
Thread.sleep(100);
} while (future1.isDone() && future2.isDone() && future3.isDone());
log.info("猎取异步要领的返回值:{}", future1.get());
Thread.sleep(5000);
long end = System.currentTimeMillis();
log.info("主程序实行完成耗时{}秒", (end - start)/1000f);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运转测试类,我们能够看到使命一二三异步实行了,主使命末了实行完成,而且能够猎取到使命的返回信息。
源码地点:https://github.com/imyanger/springboot-project/tree/master/p23-springboot-async