使用CompletableFuture.allOf实现异步执行同步搜集结果
需求
- 采用多线程执异步行某种任务,比如在不同主机查询磁盘列表信息。
- 将执行结果搜集,分组分类,处理。
- 将处理以后的结果给予展示。
解决方案
- countdownlatch
- CompletableFuture
使用CompletableFuture
定义FutureTaskWorker
package com;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author gang.tu
* @ClassName FutureTaskWorker
* @Description 异步执行同步返回
*/
@Data
@AllArgsConstructor
public class FutureTaskWorker<T, R> {
/**
* @description 需要异步执行的任务
*/
private List<T> taskList;
/**
* @description 需要执行的方法
*/
private Function<T, CompletableFuture<R>> workFunction;
/**
* @description 搜集执行结果
* @author gang.tu
* @return: java.util.List<R>
*/
public List<R> getAllResult() {
List<CompletableFuture<R>> futureList = taskList.stream().map(workFunction).collect(Collectors.toList());
CompletableFuture<Void> allCompletableFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
return allCompletableFuture.thenApply(e -> futureList.stream().map(CompletableFuture::join).collect(Collectors.toList())).join();
}
}
单元测试
package com;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* @author gang.tu
* @ClassName FutureTaskTest
*/
public class FutureTaskWorkerTest {
@Test
public void getAllResult() {
List<Long> list = new ArrayList<>(3);
list.add(1000l);
list.add(2000l);
list.add(3000l);
FutureTaskWorker<Long,String> futureTaskWorker = new FutureTaskWorker<>(list,(Long e)->getThreadName(e));
long begin = System.currentTimeMillis();
List<String> allResult=futureTaskWorker.getAllResult();
long end = System.currentTimeMillis();
System.out.println(allResult);
System.out.println("结束耗时:"+(end-begin));
}
private CompletableFuture<String> getThreadName(long sleepTime) {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(sleepTime);
System.out.println(Thread.currentThread().getName()+"已经睡眠"+sleepTime+"毫秒");
return Thread.currentThread().getName();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
}
运行效果截图
注意
- 此方案不适合长时间占用io的操作。
- 如果有大量请求,请注意控制线程数量,不然可能导致OOM。
- 实现workFunction时可以自定义线程池而不是用默认的ForkJoinPool