CompletableFuture 是 java 8新增的,主要用来异步编程,使用时有一些需要注意到地方,下面的代码中已经备注
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class FutureDemo {
private static final int MAX_THREADS = 400;
private final Random random = new Random();
private final Executor executor;
private final int taskCount;
FutureDemo(int taskCount) {
this.taskCount = taskCount;
executor = Executors.newFixedThreadPool(Math.min(taskCount, MAX_THREADS), r -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
});
}
private void delay(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private double task1(int a) {
delay(100);
return Math.pow(a, 2);
}
private int task2(double a) {
// delay();
return (int) Math.sqrt(a);
}
private char task3(int i) {
int ms = 10 + random.nextInt(90);
delay(ms);
return (char) (i - 1 + 'A');
}
private void testCase1() {
measure("testCase1()", () -> {
List<CompletableFuture<Double>> futureList = IntStream.rangeClosed(1, taskCount)
.mapToObj(i -> CompletableFuture.supplyAsync(() -> task1(i), executor))
.collect(Collectors.toList());
List<Double> results = futureList.stream()
.map(CompletableFuture::join).//等待所有异步操作完成
collect(Collectors.toList());
System.out.println(results);
});
}
// Stream 结合 CompletableFuture 实现流水线式的异步任务
private void testCase2() {
measure("testCase2()", () -> {
/*todo 知识点
* thenCompose 后面的任务需要以前面的任务的输出作为输入
* thenCombine 组合两个独立的任务,合并两个任务的输出
* orTimeout 指定任务的超时时间,超时后会抛出 TimeoutException
* completeOnTimeout 指定任务的超时时间,超时后用指定的默认值作为输出
* */
List<CompletableFuture<Character>> futureList = IntStream.rangeClosed(1, taskCount)
.mapToObj(i -> CompletableFuture.supplyAsync(() -> task1(i), executor))
.map(future -> future.thenApply(this::task2))// task2 不怎么耗时,采用同步操作
// .map(future -> future.thenCompose(i -> CompletableFuture.supplyAsync(() -> task3(i), executor)))
.map(future -> future.thenApplyAsync(this::task3, executor)
//.orTimeout(300, TimeUnit.MILLISECONDS)
.completeOnTimeout('*', 220, TimeUnit.MILLISECONDS)
)
.collect(Collectors.toList());
/*List<Character> results = futureList.stream()
.map(CompletableFuture::join).//等待所有异步操作完成
collect(Collectors.toList());
System.out.println(results);*/
/*todo 知识点
* thenAccept 每个任务完成时触发,有的时候不需要等所有任务都完成才执行某些操作(如分页加载,进度更新等)
* 如果需要监听所有任务都已完成,可以使用 CompletableFuture.allOf(futures).join()
* 有些时候只要有一个任务完成即可满足需求,可以使用 CompletableFuture.anyOf(futures)
* 注:创建 futures 只是创建了一组待执行的任务,真正触发任务执行的是 join 方法
* */
long start = System.currentTimeMillis();
CompletableFuture[] futures = futureList.stream()
.map(future -> future.thenAccept(character -> {
long time = System.currentTimeMillis() - start;
System.out.println("单个任务完成:" + character + ",耗时:" + time + "ms");
}))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();//等待所有异步操作完成
//如果 future 添加了 thenAccept 监听,返回的结果将是null
// Object o = CompletableFuture.anyOf(futures).join();
// System.out.println(o);
});
}
public static void measure(String s, Runnable r) {
long start = System.currentTimeMillis();
r.run();
long end = System.currentTimeMillis();
System.out.println(s + " 用时 " + (end - start) + " ms");
}
public static void main(String[] args) {
System.out.println("availableProcessors: " + Runtime.getRuntime().availableProcessors());
final int taskCount = 26;
FutureDemo futureDemo = new FutureDemo(taskCount);
// futureDemo.testCase1();
futureDemo.testCase2();
}
}