一、为什么要并发执行多个任务,而不是一个个顺序执行呢?
比如一个接口执行了A、B、C三个任务,分别耗时1、2、3秒,如果顺序执行的话,总耗时需要6秒,代码如下:
public class TestExecuteClass {
@Test
public void entrance() {
String resultA = executeTaskA();
String resultB = executeTaskB();
String resultC = executeTaskC();
// ...
}
public String executeTaskA() {
// 耗时1s
}
public String executeTaskB() {
// 耗时2s
}
public String executeTaskC() {
// 耗时3s
}
}
很明显会很慢,也不会完全发挥我们多CPU的优势。所以如果我们可以并行执行这几个任务,再阻塞去获取执行结果,那么总耗时是会大大减少的。
二、如何并发执行多个任务并等待执行结果?
1、使用线程池(常用)
使用线程池可以使用多个线程并行执行多个任务,来充分发挥多CPU的优势,代码如下:
public class TestExecuteClass {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public void entrance() throws Exception{
Future<String> futureA = executor.submit(()->executeTaskA());
Future<String> futureB = executor.submit(()->executeTaskB());
Future<String> futureC = executor.submit(()->executeTaskC());
String resultA = futureA.get();
String resultA = futureA.get();
String resultA = futureA.get();
// ...
}
public String executeTaskA() {
// 耗时1s
}
public String executeTaskB() {
// 耗时2s
}
public String executeTaskC() {
// 耗时3s
}
}
2、使用CompletableFuture
CompletableFuture是JDK8引入的异步编程工具量类,代码如下:
public class TestExecuteClass {
public void entrance() {
CompleatableFuture<String> futureA = CompletableFuture.supplyAsync(()-> executeTaskA());
CompleatableFuture<String> futureB = CompletableFuture.supplyAsync(()-> executeTaskB());
CompleatableFuture<String> futureC = CompletableFuture.supplyAsync(()-> executeTaskC());
String resultA = futureA.get();
String resultB = futureB.get();
String resultC = futureC.get();
// ...
}
public String executeTaskA() {
// 耗时1s
}
public String executeTaskB() {
// 耗时2s
}
public String executeTaskC() {
// 耗时3s
}
}
3、使用CountDownLatch
CountDownLatch是Java中的一个同步类,在构造的时候指定一个计数值,表示需要等待的事件数量(每当一个事件到达,则计数值减一)。当计数值减为零时,当前线程才会继续被唤醒执行。
public class TaskExecuteClass {
public void entrance() throws Exception{
// 创建计数值为3的CountDownLatch,表示需要等待3个事件完成才能继续执行
CountDownLatch countDownLatch = new CountDownLatch(3);
executeTaskA();
executeTaskB();
executeTaskC();
// 阻塞,直到3个事件完成才能继续执行
countDownLatch.await();
// ...
}
public String executeTaskA() {
// 耗时1s
}
public String executeTaskB() {
// 耗时2s
}
public String executeTaskC() {
// 耗时3s
}
}