CompletableFuture: 组合式异步编程
1.先了解下什么是吞吐量:
吞吐量是指对网络、设备、端口、虚电路或其他设施,单位时间内成功地传送数据的数量(以比特、字节、分组等测量)。(百科)
2.并发,并行:
并发:单个处理器核在多个任务之间切换处理
并行:多个处理器核同时处理多个任务
Future 接口
Future接口建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个运用hui被返回调用方。
(简单说就是你去奶茶店排队买奶茶,店员给你一个序号,你就不用在那里等待,可以去做其他事,等好了再去拿,这就是异步)
例子:
ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<Double>() {
public Double call() {
return doSomeLongComputation();
}});
doSomethingElse();
try {
Double result = future.get(2, TimeUnit.SECONDS);
} catch (Exception e) {
// 计算抛出一个异常
}

使用 CompletableFuture 构建异步应用
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
}, executorService);
System.out.println("主线程: " + Thread.currentThread().getName());
future.get(2, TimeUnit.SECONDS);
结果:
主线程: main
pool-1-thread-1
(2)supplyAsync方法: 异步创建一个有返回值的CompleteFuture
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService);
System.out.println("主线程: " + Thread.currentThread().getName());
Integer integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
结果:
主线程: main
pool-1-thread-1
4
(3)thenApply, thenAccept, thenRun,这三个都是同步操作
thenApply() 监听future返回,调用Future方法对返回值业务逻辑操作,这个操作有返回值,比如转换类型
thenAccept() 监听future返回,调用Consumer处理返回值,处理的结果没有返回值,比如打印结果,返回值为CompletableFuture<void>
thenRun() 监听future返回,然后自己自定义处理,返回值为CompletableFuture<void>
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApply(f ->{
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
});
CompletableFuture<Void> voidCompletableFuture = future.thenAccept(f -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
});
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRun(() -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
});
System.out.println("主线程: " + Thread.currentThread().getName());
String integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
pool-1-thread-1
主线程: main
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-1
thenRun: +
4aaa
(4)thenApplyAsync, thenAcceptAsync, thenRunAsync,同上面三个对应,是异步操作
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApplyAsync(f ->{
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
}, executorService);
CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
}, executorService);
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
}, executorService);
System.out.println("主线程: " + Thread.currentThread().getName());
String integer = future.get(2, TimeUnit.SECONDS);
System.out.println(integer);
pool-1-thread-1
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
主线程: main
pool-1-thread-1
thenRun: +
4aaa
注意:这里是同一个线程,主要是因为这里线程池我用的是可缓存的线程池,线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。我们可以让线程睡眠一点时间
修改下代码:
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenApplyAsync(f ->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenApply: + " + f);
return String.valueOf(f) + "aaa";
}, executorService);
CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenAccept: + " + f);
}, executorService);
CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
System.out.println("thenRun: + ");
}, executorService);
System.out.println("主线程: " + Thread.currentThread().getName());
String integer = future.get(4, TimeUnit.SECONDS);
voidCompletableFuture.get();
voidCompletableFuture1.get();
System.out.println(integer);
主线程: main
pool-1-thread-1
pool-1-thread-2
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-2
thenRun: +
4aaa
可以看到还是存在有些线程已经完成并且被复用了,可以再试试把睡眠时间调整为不一样试试。
(3) thenCompose方法 多层结构的future返回一个结果,跟java8的flatmap差不多
CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService).thenCompose(f -> CompletableFuture.supplyAsync(() -> f + "dddd", executorService));
System.out.println(stringCompletableFuture.get());
pool-1-thread-2
4dddd
(4)thenCombine与thenAcceptBoth, 合并两个future,thenCombine有返回值,thenAcceptBoth没有返回值
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 4;
}, executorService);
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
return 5;
}, executorService);
CompletableFuture<Integer> f3 = f1.thenCombine(f2, (s1, s2) -> {
System.out.println(String.format("%d,%d", s1, s2));
return s1 + s2;
});
System.out.println(f3.get());
CompletableFuture<Void> f4 = f1.thenAcceptBoth(f2, (s1, s2) -> {
System.out.println(String.format("%d,%d", s1, s2));
});
System.out.println(f4.get());
pool-1-thread-1
pool-1-thread-2
4,5
9
4,5
null
(5) allOf anyOf
allOf CompleteableFuture数组里面全部完成才返回结果
ExecutorService executorService = Executors.newCachedThreadPool();
List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
return i + "s";
}, executorService)).collect(Collectors.toList());
CompletableFuture<Void> f1 = CompletableFuture.allOf(list.toArray(new CompletableFuture[]{}));
System.out.println("全部已经完成了!!" + f1.get());
pool-1-thread-1sleep :0s
pool-1-thread-2sleep :1000s
pool-1-thread-3sleep :2000s
pool-1-thread-4sleep :3000s
pool-1-thread-5sleep :4000s
pool-1-thread-6sleep :5000s
pool-1-thread-7sleep :6000s
pool-1-thread-8sleep :7000s
pool-1-thread-9sleep :8000s
pool-1-thread-10sleep :9000s
pool-1-thread-11sleep :10000s
全部已经完成了!!null
anyOf CompleteableFuture数组里面其中一个完成就返回结果
ExecutorService executorService = Executors.newCachedThreadPool();
List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
return i + "s";
}, executorService)).collect(Collectors.toList());
CompletableFuture<Object> f1 = CompletableFuture.anyOf(list.toArray(new CompletableFuture[]{}));
System.out.println("其中一个已经完成了!!" + f1.get());
pool-1-thread-1sleep :0s
其中一个已经完成了!!0s