2、@Async

==========================================================================

需要注意的,@Async在使用上有一些限制:

  • 它只能应用于public修饰的方法
  • 自调用–从同一个类中调用async方法,将不起作用

原因很简单:

  • 只有公共方法,才可以被代理。
  • 自调用不起作用,因为它越过了代理直接调用了方法。

2.1、无返回值的异步方法


这是一个异步运行的无返回值方法:

@Async
public void asyncMethodWithVoidReturnType() {
System.out.println("异步无返回值方法 "
• Thread.currentThread().getName());
}
实例:
• AsyncTask:异步式任务类,定义了三个异步式方法。
/**
• @Author 三分恶
• @Date 2020/7/15
• @Description 异步式任务
*/
@Component
public class AsyncTask {
Logger log= LoggerFactory.getLogger(AsyncTask.class);
private Random random = new Random();
/**
• 定义三个异步式方法
• @throws InterruptedException
*/
@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);
}
}
• 在测试类中调用三个异步式方法:
/**
• @Author 三分恶
• @Date 2020/7/15
• @Description
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class AsyncTaskTest {
@Autowired
private AsyncTask asyncTask;
Logger log= LoggerFactory.getLogger(AsyncTaskTest.class);
@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();
}
}
}

运行结果:可以看到三个方法没有顺序执行,这个复执行单元测试,您可能会遇到各种不同的结果,比如:

  • 没有任何任务相关的输出
  • 有部分任务相关的输出
  • 乱序的任务相关的输出

springboot函数调用_springboot函数调用

springboot函数调用_笔记_02

原因是目前doTaskOne、doTaskTwo、doTaskThree三个函数的时候已经是异步执行了。**主程序在异步调用之后,主程序并不会理会这三个函数是否执行完成了,由于没有其他需要执行的内容,所以程序就自动结束了,**导致了不完整或是没有输出任务相关内容的情况。

2.1、有返回值的异步方法


@Async也可以应用有返回值的方法–通过在Future中包装实际的返回值:

/**
• 有返回值的异步方法
• @return
*/
@Async
public Future asyncMethodWithReturnType() {
System.out.println("执行有返回值的异步方法 "
• Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult(“hello world !!!”);
} catch (InterruptedException e) {
//
}
return null;
}
Spring还提供了一个实现Future的AsyncResult类。这个类可用于跟踪异步方法执行的结果。
实例:
• 我们将2.1的实例改造成有返回值的异步方法:
@Async
public Future taskOne() throws InterruptedException {
long start = System.currentTimeMillis();
//随机休眠若干毫秒
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info(“任务一执行完成耗时{}秒”, (end - start)/1000f);
return new AsyncResult<>(“任务一完事了”);
}
taskTwo、taskThree方法做同样的改造。
• 测试有返回值的异步方法:
@Test
public void doFutureTask(){
try {
long start=System.currentTimeMillis();
Future future1=asyncTask.taskOne();
Future future2 = asyncTask.taskTwo();
Future future3 = asyncTask.taskThree();
//三个任务执行完再执行主程序
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();
}
}

运行结果:可以看到三个任务完成后才执行主程序,还输出了异步方法的返回值。

springboot函数调用_笔记_03

3、 Executor

=============================================================================

默认情况下,Spring使用SimpleAsyncTaskExecutor异步运行这些方法。

可以在两个级别上重写默认线程池——应用程序级别或方法级别。