使用之前先要定义一个线程池,也可不定义使用默认的线程池,这里先简单定义一个线程池。
ExecutorService executor = Executors.newFixedThreadPool(10);
异步调用方式
1.supplyAsync()有返回值
/**
* supplyAsync:有返回值
*/
@Test
public void test5() throws Exception {
System.out.println("主线程开始:" + Thread.currentThread().getName());
CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
{
//执行任务
System.out.println("子线程:" + Thread.currentThread().getName() + "正在执行任务...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "子线程执行完成...";
}, executor);
System.out.println("获取返回值:" + future.get());
System.out.println("主线程结束:" + Thread.currentThread().getName());
}
2.runAsync()无返回值
/**
* runAsync:无返回值
*/
@Test
public void test4() throws ExecutionException, InterruptedException {
System.out.println("主线程开始:" + Thread.currentThread().getName());
CompletableFuture<Void> future = CompletableFuture.runAsync(() ->
{
//执行任务
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程:" + Thread.currentThread().getName() + ":正在执行任务...");
}, executor);
System.out.println("获取返回值:" + future.get());
System.out.println("主线程结束:" + Thread.currentThread().getName());
}
future.get()方法是获取异步线程的返回值,会使主线程阻塞直到获取结果。
多任务结果处理
1.allOf()方法
CompletableFuture.allOf()方法会收集所有异步处理结果,join()方法会阻塞等待所有线程执行完毕。
@Test
public void test5() throws InterruptedException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() ->
{
System.out.println("商品名称");
return "华为手机";
}, TestAsync.executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() ->
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("商品属性");
return "8G+256G";
}, TestAsync.executor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() ->
{
System.out.println("商品价格");
return "4999元";
}, TestAsync.executor);
//收集所有异步处理结果
CompletableFuture<Void> futures = CompletableFuture.allOf(future1, future2, future3);
//阻塞等待所有任务执行结束,返回结果为null
System.out.println(futures.join());
System.out.println("=====主线程=====");
Thread.sleep(500);
//join()获取结果不再阻塞
System.out.println(future1.join() + ":" + future2.join() + ":" + future3.join());
}
2.anyOf()方法
CompletableFuture.anyOf()的含义是只要有任意一个CompletableFuture结束,就可以获取结果做接下来的事情,而无须像AllOf()那样,等待所有的任务结束。
@Test
public void test6() {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() ->
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("商品名称");
return "华为手机";
}, TestAsync.executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() ->
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("商品属性");
return "8G+256G";
}, TestAsync.executor);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() ->
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("商品价格");
return "4999元";
}, TestAsync.executor);
CompletableFuture<Object> futures = CompletableFuture.anyOf(future1, future2, future3);
//阻塞等待最先的任务执行完成,返回最先完成的任务返回结果,无需等待所有任务执行完成
System.out.println("执行结果: " + futures.join());
System.out.println("=====主线程=====");
}
异步结果回调处理
1.thenApply()和thenApplyAsync()
此方法表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,回调方法有返回值。
(1).thenApplyAsync()测试代码:
@Test
public void test4() throws ExecutionException, InterruptedException {
System.out.println("主线程名: " + Thread.currentThread().getName());
//父任务
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("父线程名: " + Thread.currentThread().getName());
return 1;
});
//子任务
CompletableFuture<Integer> cf2 = cf1.thenApplyAsync((result) -> {
System.out.println("子线程名: " + Thread.currentThread().getName());
result += 2;
return result;
});
//等待父任务执行完成
System.out.println("父任务结果-> " + cf1.get());
//等待子任务执行完成
System.out.println("子任务结果-> " + cf2.get());
}
测试结果分析:使用thenApplyAsync()回调方法,父任务线程和子任务线程用的是默认线程池中的同一个线程。
(2).thenApply()测试代码:
@Test
public void test5() throws ExecutionException, InterruptedException {
System.out.println("主线程名: " + Thread.currentThread().getName());
//父任务
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("父线程名: " + Thread.currentThread().getName());
return 1;
});
//子任务
CompletableFuture<Integer> cf2 = cf1.thenApply((result) -> {
System.out.println("子线程名: " + Thread.currentThread().getName());
result += 2;
return result;
});
//等待父任务执行完成
System.out.println("父任务结果-> " + cf1.get());
//等待子任务执行完成
System.out.println("子任务结果-> " + cf2.get());
}
测试结果分析:使用thenApply()回调方法,父任务线程用的是默认线程池中的线程,子任务用的是主线程。
2.thenAccept()和thenAcceptAsync()
此方法与上面的两个方法区别是回调方法没有返回值。
(1).thenAccept()测试代码:
@Test
public void test6() throws ExecutionException, InterruptedException {
System.out.println("主线程名: " + Thread.currentThread().getName());
//父任务
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("父线程名: " + Thread.currentThread().getName());
return 1;
});
//子任务
CompletableFuture<Void> cf2 = cf1.thenAccept((result) -> {
System.out.println("子线程名: " + Thread.currentThread().getName());
});
//等待父任务执行完成
System.out.println("父任务结果->" + cf1.get());
//等待子任务执行完成
System.out.println("子任务结果->" + cf2.get());
}
测试结果分析:使用thenAccept()回调方法,父任务线程用的是默认线程池中的线程,子任务用的是主线程。
(2).thenAcceptAsync()测试代码:
@Test
public void test7() throws ExecutionException, InterruptedException {
System.out.println("主线程名: " + Thread.currentThread().getName());
//父任务
CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("父线程名: " + Thread.currentThread().getName());
return 1;
});
//子任务
CompletableFuture<Void> cf2 = cf1.thenAcceptAsync((result) -> {
System.out.println("子线程名: " + Thread.currentThread().getName());
});
//等待父任务执行完成
System.out.println("父任务结果->" + cf1.get());
//等待子任务执行完成
System.out.println("子任务结果->" + cf2.get());
}
测试结果分析:使用thenAcceptAsync()回调方法,父任务线程和子任务线程用的是默认线程池中的同一个线程。
3.exceptionally()
exceptionally()方法表示任务执行异常时执行的回调方法,并且有抛出异常作为参数,传递到回调方法,测试代码:
@Test
public void test6() throws ExecutionException, InterruptedException {
CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
double random = Math.random();
if (random < 0.5) {
int i = 5 / 0;
}
System.out.println("正常结束");
return random;
}).exceptionally(e -> {
//发生异常后才会执行
System.out.println("异常信息: " + e.getMessage());
return Math.random();
});
System.out.println(future.get());
}
测试结果:
(1).正常情况:
(2).异常情况:
以上可看出,supplyAsync()方法发生异常才会执行exceptionally()方法。
实例应用
private List<MediaFileDTO> ossSupplyAsync(List<MediaFileDTO> records) {
List<CompletableFuture<MediaFileDTO>> futureList = new ArrayList<>();
List<MediaFileDTO> listData = new ArrayList<>();
records.forEach(record -> {
CompletableFuture<MediaFileDTO> future = CompletableFuture.supplyAsync(() -> {
if (record.getFileName().endsWith(".jpeg") || record.getFileName().endsWith(".jpg")) {
String objectKey = record.getObjectKey();
record.setResizeUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket,
objectKey.substring(0, objectKey.indexOf(".")) + "_resize"
+ objectKey.substring(objectKey.indexOf("."))));
} else {
record.setResizeUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, record.getObjectKey(),
OssProcessEnum.RESIZE.getStyle()));
}
record.setOriginUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, record.getObjectKey()));
return record;
}, threadPoolExecutor);
futureList.add(future);
});
futureList.forEach(future -> listData.add(future.join()));
return listData;
}