// CompletableFuture 实现了Future、CompletionStage两个接口
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
以下是对源码描述的翻译(需要细品):
由于 FutureTask 的2个缺点,JDK8设计出了CompletableFuture,CompletableFuture 提供了一种类似观察者模式的机制,
可以让异步任务完成后回调通知监听的一方,可以避免阻塞和轮询
CompletableFuture 优点:
异步任务或异常,会自动回调某个对象的方法
主线程设置好回调后,不再关心异步任务的执行,异步任务之间也可以顺序执行
以下是对源码描述的翻译(需要细品):
runAsync 执行的任务无返回值,
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
supplyAsync 执行的任务有返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
以上传入 Executor 可以使用我们指定的线程池,不传则使用默认的 ForkJoinPool.commonPool()线程池
CompletableFuture 源码:
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
// 默认线程池 —— ForkJoinPool.commonPool() 除非它不支持并行。
private static final Executor asyncPool = useCommonPool ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
// 如果 ForkJoinPool.commonPool() 不支持并行性,则回退
static final class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
// 返回一个新的 CompletableFuture,它在运行给定操作后由 ForkJoinPool.commonPool() 中运行的任务异步完成。
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
// 返回一个新的 CompletableFuture,它由在 ForkJoinPool.commonPool() 中运行的任务异步完成,调用者可以获取返回值。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
}
测试 1:
@Slf4j(topic = "c.TestsSupplyAsync")
public class TestsSupplyAsync {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(3);
CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
log.debug("线程名:{}", Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello supplyAsync";
}, pool);
log.debug("{}", supplyAsync.get());
// 也可以使用join,使用join可以不用声明异常
// log.debug("{}", supplyAsync.join());
pool.shutdown();
}
}
17:52:23.694 c.TestsSupplyAsync [pool-1-thread-1] - 线程名:pool-1-thread-1
17:52:24.706 c.TestsSupplyAsync [main] - hello supplyAsync
测试 2:
需求:
public class TestCompletableFuture {
static List<Mall> list = Arrays.asList(
new Mall("JD"),
new Mall("DangDang"),
new Mall("TaoBao")
);
public static void main(String[] args) {
long start = System.currentTimeMillis();
List<String> price = getPrice(list, "java");
price.forEach(System.out::println);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "毫秒");
}
// List -> List> -> List
public static List<String> getPrice(List<Mall> mallList, String bookName) {
return mallList.stream()
.map(mall -> CompletableFuture.supplyAsync(() ->
String.format(bookName + " in %s price is %.2f",
mall.getMallName(),
mall.getBookPrice(bookName))))
.collect(Collectors.toList())
.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
}
class Mall {
@Getter
private final String mallName;
public Mall(String mallName) {
this.mallName = mallName;
}
public double getBookPrice(String bookName){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 随机产生价格
return ThreadLocalRandom.current().nextDouble() * 2 + bookName.charAt(0);
}
}
java in JD price is 106.31
java in DangDang price is 106.35
java in TaoBao price is 107.81
耗时:1125毫秒
// 等待任务完成,并返回结果
public T get() throws InterruptedException, ExecutionException
// 带超时的等待,并返回结果,超时则抛出异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
// 等待任务完成,并返回结果,不用声明异常 (编译时不会检查异常)
// 出现异常时,抛出 CompletionException 异常
public T join()
// 如果任务完成则返回结果值(或抛出任何遇到的异常),否则返回给定的参数值 valueIfAbsent
// 不会阻塞
public T getNow(T valueIfAbsent)
测试 getNow()
public static void main(String[] args) {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "测试getNow方法";
});
System.out.println("结果:" + completableFuture.getNow("这是任务没完成返回的指定值"));
}
结果:这是任务没完成返回的指定值
// 如果尚未完成,则将 get() 和相关方法返回的值设置为给定值
// 表示是否打断get()、join()等方法,立即返回指定值 value
public boolean complete(T value)
测试 complete():
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
// 执行 2s
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "测试getNow方法";
});
// 等 1s
TimeUnit.SECONDS.sleep(1);
// 是否打断get()等方法
boolean flag = completableFuture.complete("这是任务没完成返回的指定值");
String value = completableFuture.get();
System.out.println("是否打断:" + flag + ", 结果:" + value);
}
是否打断:true, 结果:这是任务没完成返回的指定值
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
测试正常情况:
@Slf4j(topic = "c.TestThenApply")
public class TestThenApply {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
log.debug("第一阶段");
return 1;
}, pool).thenApply((v) -> {
log.debug("第二阶段");
return v + 2;
}).thenApply((v) -> {
log.debug("第三阶段");
return v + 3;
}).whenComplete((v, e) -> {
log.debug("结果:" + v);
}).exceptionally(e -> {
log.debug("出现异常:" + e.getMessage());
return null;
});
pool.shutdown();
}
}
22:45:39.496 c.TestThenApply [pool-1-thread-1] - 第一阶段
22:45:39.499 c.TestThenApply [pool-1-thread-1] - 第二阶段
22:45:39.499 c.TestThenApply [pool-1-thread-1] - 第三阶段
22:45:39.500 c.TestThenApply [pool-1-thread-1] - 结果:6
测试异常情况:
@Slf4j(topic = "c.TestThenApply")
public class TestThenApply {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
log.debug("第一阶段");
return 1;
}, pool).thenApply((v) -> {
int i = 10 / 0;
log.debug("第二阶段");
return v + 2;
}).thenApply((v) -> {
log.debug("第三阶段");
return v + 3;
}).whenComplete((v, e) -> {
log.debug("结果:" + v);
}).exceptionally(e -> {
log.debug("出现异常:" + e.getMessage());
return null;
});
pool.shutdown();
}
}
22:46:05.153 c.TestThenApply [pool-1-thread-1] - 第一阶段
22:46:05.158 c.TestThenApply [pool-1-thread-1] - 结果:null
22:46:05.158 c.TestThenApply [pool-1-thread-1] - 出现异常:java.lang.ArithmeticException: / by zero
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
测试正常情况:
@Slf4j(topic = "c.TestHandle")
public class TestHandle {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
log.debug("第一阶段");
return 1;
}, pool).handle((v, e) -> {
log.debug("第二阶段");
return v + 2;
}).handle((v, e) -> {
log.debug("第三阶段");
if (e != null) {
log.debug("捕获上一阶段的异常:" + e.getMessage());
}
return v + 3;
}).whenComplete((v, e) -> {
log.debug("结果:" + v);
}).exceptionally(e -> {
log.debug("出现异常:" + e.getMessage());
return null;
});
pool.shutdown();
}
}
22:39:52.103 c.TestHandle [pool-1-thread-1] - 第一阶段
22:39:52.107 c.TestHandle [pool-1-thread-1] - 第二阶段
22:39:52.107 c.TestHandle [pool-1-thread-1] - 第三阶段
22:39:52.107 c.TestHandle [pool-1-thread-1] - 结果:6
测试异常情况:
@Slf4j(topic = "c.TestHandle")
public class TestHandle {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
log.debug("第一阶段");
return 1;
}, pool).handle((v, e) -> {
int i = 10 / 0;
log.debug("第二阶段");
return v + 2;
}).handle((v, e) -> {
log.debug("第三阶段");
if (e != null) {
log.debug("捕获上一阶段的异常:" + e.getMessage());
}
return v + 3;
}).whenComplete((v, e) -> {
log.debug("结果:" + v);
}).exceptionally(e -> {
log.debug("出现异常:" + e.getMessage());
return null;
});
pool.shutdown();
}
}
22:41:21.347 c.TestHandle [pool-1-thread-1] - 第一阶段
22:41:21.352 c.TestHandle [pool-1-thread-1] - 第三阶段
22:41:21.352 c.TestHandle [pool-1-thread-1] - 捕获上一阶段的异常:java.lang.ArithmeticException: / by zero
22:41:21.353 c.TestHandle [pool-1-thread-1] - 结果:null
22:41:21.353 c.TestHandle [pool-1-thread-1] - 出现异常:java.lang.NullPointerException
注意: 出现的空指针异常(v为null,出现在 return v + 2; 和 return v + 3;两处地方)
public <U> CompletionStage<U> thenApply(Function<? super T, ? extends U> fn);
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
这两个方法的返回值都是CompletionStage,只是传入函数fn不同
对于thenApply,fn函数是对一个已完成的CompletionStage的返回值进行计算、操作
对于thenCompose,fn函数是对新创建的CompletionStage进行计算、操作
测试:
public static void main(String[] args) {
CompletableFuture<String> thenApply = CompletableFuture.supplyAsync(() -> 1)
.thenApply(v -> "将Integer类型值:" + v + ",转换成字符串");
CompletableFuture<String> thenCompose = CompletableFuture.supplyAsync(() -> 1)
.thenCompose(v -> CompletableFuture.supplyAsync(() -> "新创建一个CompletableFuture将Integer类型值:" + v + ",转换成字符串"));
System.out.println("thenApply:" +thenApply.join());
System.out.println("thenCompose:" + thenCompose.join());
}
thenApply:将Integer类型值:1,转换成字符串
thenCompose:新创建一个CompletableFuture将Integer类型值:1,转换成字符串
whenComplete 源码:
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
测试:
@Slf4j(topic = "c.TestWhenComplete")
public class TestWhenComplete {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> {
// 随机数
int i = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("1s后返回结果:{}", i);
return i;
}).whenComplete((v, e) -> {
if (e == null) {
log.debug("没有异常,获取结果:{}", v);
}
}).exceptionally(e -> {
log.debug("出现异常:{}", e.getMessage());
return null;
});
log.debug("主线程去执行其他任务。。。");
log.debug("主线程执行完成");
}
}
18:18:51.912 c.TestWhenComplete [main] - 主线程去执行其他任务。。。
18:18:51.916 c.TestWhenComplete [main] - 主线程执行完成
Process finished with exit code 0
由结果可以看出,主线程停止后,子线程也随之停止
由于ForkJoinPool.commonPool()类似守护线程,还没执行完就随主线程一起关闭了
解决方法:
1. 让主线程执行完后,停留一段时间
2. 传入自定义线程池
@Slf4j(topic = "c.TestWhenComplete")
public class TestWhenComplete {
public static void main(String[] args) throws InterruptedException {
CompletableFuture.supplyAsync(() -> {
// 随机数
int i = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("1s后返回结果:{}", i);
return i;
}).whenComplete((v, e) -> {
if (e == null) {
log.debug("没有异常,获取结果:{}", v);
}
}).exceptionally(e -> {
log.debug("出现异常:{}", e.getMessage());
return null;
});
log.debug("主线程去执行其他任务。。。");
log.debug("主线程执行完成");
// 默认的线程池 —— ForkJoinPool.commonPool()类似守护线程,主线程关闭后,也会随之关闭
TimeUnit.SECONDS.sleep(2);
log.debug("主线程阻塞2s");
}
}
18:23:24.503 c.TestWhenComplete [main] - 主线程去执行其他任务。。。
18:23:24.506 c.TestWhenComplete [main] - 主线程执行完成
18:23:25.509 c.TestWhenComplete [ForkJoinPool.commonPool-worker-9] - 1s后返回结果:8
18:23:25.511 c.TestWhenComplete [ForkJoinPool.commonPool-worker-9] - 没有异常,获取结果:8
18:23:26.519 c.TestWhenComplete [main] - 主线程阻塞2s
Process finished with exit code 0
@Slf4j(topic = "c.TestWhenComplete")
public class TestWhenComplete {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = null;
try {
pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
// 随机数
int i = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("1s后返回结果:{}", i);
return i;
// 传入自定义线程池
}, pool).whenComplete((v, e) -> {
if (e == null) {
log.debug("没有异常,获取结果:{}", v);
}
}).exceptionally(e -> {
log.debug("出现异常:{}", e.getMessage());
return null;
});
log.debug("主线程去执行其他任务。。。");
log.debug("主线程执行完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
pool.shutdown();
}
}
}
18:37:39.968 c.TestWhenComplete [main] - 主线程去执行其他任务。。。
18:37:39.970 c.TestWhenComplete [main] - 主线程执行完成
18:37:40.973 c.TestWhenComplete [pool-1-thread-1] - 1s后返回结果:1
18:37:40.975 c.TestWhenComplete [pool-1-thread-1] - 没有异常,获取结果:1
@Slf4j(topic = "c.TestWhenComplete")
public class TestWhenComplete {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = null;
try {
pool = Executors.newFixedThreadPool(3);
CompletableFuture.supplyAsync(() -> {
// 随机数
int i = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("1s后返回结果:{}", i);
if (i > 2) {
// 模拟异常
i = 10/0;
}
return i;
// 传入自定义线程池
}, pool).whenComplete((v, e) -> {
if (e == null) {
log.debug("没有异常,获取结果:{}", v);
} else {
log.debug("捕获上一阶段异常:{}", e.getMessage());
}
}).exceptionally(e -> {
log.debug("出现异常:{}", e.getMessage());
return null;
});
log.debug("主线程去执行其他任务。。。");
log.debug("主线程执行完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
pool.shutdown();
}
}
}
00:04:32.849 c.TestWhenComplete [main] - 主线程去执行其他任务。。。
00:04:32.851 c.TestWhenComplete [main] - 主线程执行完成
00:04:33.849 c.TestWhenComplete [pool-1-thread-1] - 1s后返回结果:4
00:04:33.854 c.TestWhenComplete [pool-1-thread-1] - 捕获上一阶段异常:java.lang.ArithmeticException: / by zero
00:04:33.854 c.TestWhenComplete [pool-1-thread-1] - 出现异常:java.lang.ArithmeticException: / by zero
public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn);
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public CompletionStage<Void> thenAccept(Consumer<? super T> action);
测试:
@Slf4j(topic = "c.TestThenAccept")
public class TestThenAccept {
public static void main(String[] args) {
CompletableFuture<Void> thenAccept = CompletableFuture.supplyAsync(() -> {
log.debug("第一阶段");
return 1;
}).thenApply(v -> {
log.debug("第二阶段");
return v + 2;
}).thenApply(v -> {
log.debug("第三阶段");
return v + 3;
}).thenAccept(v -> {
log.debug("结果:" + v);
});
log.debug("返回结果:{}", thenAccept.join());
}
}
22:52:09.389 c.TestThenAccept [ForkJoinPool.commonPool-worker-1] - 第一阶段
22:52:09.394 c.TestThenAccept [ForkJoinPool.commonPool-worker-1] - 第二阶段
22:52:09.394 c.TestThenAccept [ForkJoinPool.commonPool-worker-1] - 第三阶段
22:52:09.394 c.TestThenAccept [ForkJoinPool.commonPool-worker-1] - 结果:6
22:52:09.394 c.TestThenAccept [main] - 返回结果:null
public CompletionStage<Void> thenRun(Runnable action);
测试:
@Slf4j(topic = "c.TestThenRun_ThenAccept_ThenApply")
public class TestThenRun_ThenAccept_ThenApply {
public static void main(String[] args) {
CompletableFuture<Void> completableFuture1 = CompletableFuture.supplyAsync(() -> {
return 1;
}).thenRun(() -> {
log.debug("做其他任务");
});
log.debug("thenRun的结果:" + completableFuture1.join());
log.debug("===================");
CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(() -> {
return 1;
}).thenAccept((v) -> {
log.debug("获取上一阶段的值:" + v);
});
log.debug("thenAccept的结果:" + completableFuture2.join());
log.debug("===================");
CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
return 1;
}).thenApply((v) -> {
log.debug("获取上一阶段的值:" + v);
return v + 2;
});
log.debug("thenApply的结果:" + completableFuture3.join());
}
}
22:58:08.055 c.TestThenRun_ThenAccept_ThenApply [main] - 做其他任务
22:58:08.059 c.TestThenRun_ThenAccept_ThenApply [main] - thenRun的结果:null
22:58:08.059 c.TestThenRun_ThenAccept_ThenApply [main] - ===================
22:58:08.060 c.TestThenRun_ThenAccept_ThenApply [main] - 获取上一阶段的值:1
22:58:08.061 c.TestThenRun_ThenAccept_ThenApply [main] - thenAccept的结果:null
22:58:08.061 c.TestThenRun_ThenAccept_ThenApply [main] - ===================
22:58:08.062 c.TestThenRun_ThenAccept_ThenApply [main] - 获取上一阶段的值:1
22:58:08.062 c.TestThenRun_ThenAccept_ThenApply [main] - thenApply的结果:3
注意:
由于各阶段任务做得很快,这时可能就会出现直接让main线程把任务做了,而没有开启新线程
如果在各阶段加一些休眠,可能就会开启新的线程做任务
给各阶段加休眠:
@Slf4j(topic = "c.TestThenRun_ThenAccept_ThenApply")
public class TestThenRun_ThenAccept_ThenApply {
public static void main(String[] args) {
CompletableFuture<Void> completableFuture1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
}).thenRun(() -> {
log.debug("做其他任务");
});
log.debug("thenRun的结果:" + completableFuture1.join());
log.debug("===================");
CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
}).thenAccept((v) -> {
log.debug("获取上一阶段的值:" + v);
});
log.debug("thenAccept的结果:" + completableFuture2.join());
log.debug("===================");
CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
}).thenApply((v) -> {
log.debug("获取上一阶段的值:" + v);
return v + 2;
});
log.debug("thenApply的结果:" + completableFuture3.join());
}
}
23:03:51.729 c.TestThenRun_ThenAccept_ThenApply [ForkJoinPool.commonPool-worker-1] - 做其他任务
23:03:51.732 c.TestThenRun_ThenAccept_ThenApply [main] - thenRun的结果:null
23:03:51.732 c.TestThenRun_ThenAccept_ThenApply [main] - ===================
23:03:53.734 c.TestThenRun_ThenAccept_ThenApply [ForkJoinPool.commonPool-worker-1] - 获取上一阶段的值:1
23:03:53.734 c.TestThenRun_ThenAccept_ThenApply [main] - thenAccept的结果:null
23:03:53.734 c.TestThenRun_ThenAccept_ThenApply [main] - ===================
23:03:56.735 c.TestThenRun_ThenAccept_ThenApply [ForkJoinPool.commonPool-worker-1] - 获取上一阶段的值:1
23:03:56.735 c.TestThenRun_ThenAccept_ThenApply [main] - thenApply的结果:3
thenAccept 与 thenAcceptAsync、thenApply 与 thenApplyAsync 同理
thenRunAsync 源码:
// CPU核数是否大于1
private static final boolean useCommonPool =(ForkJoinPool.getCommonPoolParallelism() > 1);
// CPU核数大于1,则使用默认线程池 ForkJoinPool.commonPool()
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
public CompletableFuture<Void> thenRunAsync(Runnable action) {
// CPU核数大于1, asyncPool 使用默认线程池 ForkJoinPool.commonPool()
return uniRunStage(asyncPool, action);
}
测试 thenRun:
@Slf4j(topic = "c.TestThenRun")
public class TestThenRun {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletableFuture<Void> completableFuture1 = CompletableFuture.supplyAsync(() -> {
log.debug("不传入自定义线程池时,supplyAsync 的线程池:" + Thread.currentThread().getName());
return 1;
}).thenRun(() -> {
log.debug("thenRun 和上一阶段使用相同的线程池:" + Thread.currentThread().getName());
});
log.debug("结果:" + completableFuture1.join());
log.debug("======================");
CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(() -> {
log.debug("传入自定义线程池时,supplyAsync 的线程池:" + Thread.currentThread().getName());
return 1;
// 传入自定义线程池
}, pool).thenRun(() -> {
log.debug("thenRun 和上一阶段使用相同的线程池:" + Thread.currentThread().getName());
});
log.debug("结果:" + completableFuture2.join());
log.debug("======================");
// 关闭线程池
pool.shutdown();
}
}
23:08:39.413 c.TestThenRun [ForkJoinPool.commonPool-worker-1] - 不传入自定义线程池时,supplyAsync 的线程池:ForkJoinPool.commonPool-worker-1
23:08:39.424 c.TestThenRun [ForkJoinPool.commonPool-worker-1] - thenRun 和上一阶段使用相同的线程池:ForkJoinPool.commonPool-worker-1
23:08:39.425 c.TestThenRun [main] - 结果:null
23:08:39.425 c.TestThenRun [main] - ======================
23:08:39.426 c.TestThenRun [pool-1-thread-1] - 传入自定义线程池时,supplyAsync 的线程池:pool-1-thread-1
23:08:39.426 c.TestThenRun [pool-1-thread-1] - thenRun 和上一阶段使用相同的线程池:pool-1-thread-1
23:08:39.426 c.TestThenRun [main] - 结果:null
23:08:39.426 c.TestThenRun [main] - ======================
测试 thenRunAsync:
@Slf4j(topic = "c.TestThenRunAsync")
public class TestThenRunAsync {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletableFuture<Void> completableFuture1 = CompletableFuture.supplyAsync(() -> {
log.debug("不传入自定义线程池时,supplyAsync 的线程池:" + Thread.currentThread().getName());
return 1;
}).thenRunAsync(() -> {
log.debug("thenRunAsync 使用默认的线程池:" + Thread.currentThread().getName());
});
log.debug("结果:" + completableFuture1.join());
log.debug("======================");
CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(() -> {
log.debug("传入自定义线程池时,supplyAsync 的线程池:" + Thread.currentThread().getName());
return 1;
// 传入自定义线程池
}, pool).thenRunAsync(() -> {
log.debug("thenRunAsync 使用默认的线程池:" + Thread.currentThread().getName());
});
log.debug("结果:" + completableFuture2.join());
log.debug("======================");
// 关闭线程池
pool.shutdown();
}
}
23:10:21.374 c.TestThenRunAsync [ForkJoinPool.commonPool-worker-1] - 不传入自定义线程池时,supplyAsync 的线程池:ForkJoinPool.commonPool-worker-1
23:10:21.377 c.TestThenRunAsync [ForkJoinPool.commonPool-worker-1] - thenRunAsync 使用默认的线程池:ForkJoinPool.commonPool-worker-1
23:10:21.377 c.TestThenRunAsync [main] - 结果:null
23:10:21.377 c.TestThenRunAsync [main] - ======================
23:10:21.378 c.TestThenRunAsync [pool-1-thread-1] - 传入自定义线程池时,supplyAsync 的线程池:pool-1-thread-1
23:10:21.378 c.TestThenRunAsync [ForkJoinPool.commonPool-worker-1] - thenRunAsync 使用默认的线程池:ForkJoinPool.commonPool-worker-1
23:10:21.378 c.TestThenRunAsync [main] - 结果:null
23:10:21.379 c.TestThenRunAsync [main] - ======================
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn);
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action);
public CompletionStage<Void> runAfterEither(CompletionStage<?> other, Runnable action);
测试 applyToEither:
@Slf4j(topic = "c.TestApplyToEither")
public class TestApplyToEither {
public static void main(String[] args) {
CompletableFuture<String> A = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("A 1s 完成任务");
return "A";
});
CompletableFuture<String> B = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("B 2s 完成任务");
return "B";
});
CompletableFuture<String> result = A.applyToEither(B, v -> v + " 先完成");
log.debug(result.join());
}
}
23:15:50.711 c.TestApplyToEither [ForkJoinPool.commonPool-worker-1] - A 1s 完成任务
23:15:50.714 c.TestApplyToEither [main] - A 先完成
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other, Runnable action);
测试 thenCombine:
@Slf4j(topic = "c.TestThenCombine")
public class TestThenCombine {
public static void main(String[] args) {
log.debug("开始");
CompletableFuture<Integer> A = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("A 完成");
return 10;
});
CompletableFuture<Integer> B = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("B 完成");
return 20;
});
CompletableFuture<Integer> result = A.thenCombine(B, (x, y) -> x + y);
log.debug("结果:" + result.join());
}
}
16:47:50.931 c.TestThenCombine [main] - 开始
16:47:51.992 c.TestThenCombine [ForkJoinPool.commonPool-worker-9] - A 完成
16:47:53.007 c.TestThenCombine [ForkJoinPool.commonPool-worker-2] - B 完成
16:47:53.007 c.TestThenCombine [main] - 结果:30
@Slf4j(topic = "c.TestThenCombine")
public class TestThenCombine {
public static void main(String[] args) {
log.debug("开始");
CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("A 完成");
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("B 完成");
return 20;
}), (x, y) -> x + y);
log.debug("结果:" + result.join());
}
}
16:53:50.817 c.TestThenCombine [main] - 开始
16:53:51.894 c.TestThenCombine [ForkJoinPool.commonPool-worker-9] - A 完成
16:53:52.886 c.TestThenCombine [ForkJoinPool.commonPool-worker-2] - B 完成
16:53:52.886 c.TestThenCombine [main] - 结果:30
测试 任务数 等于 CompletableFuture 线程池的最大线程数:
创建任务类:
@Slf4j(topic = "c.Task")
class Task {
// 任务名
private String name;
// 做该任务耗时 (秒)
private Integer productionTime;
public Task(String name, Integer productionTime) {
this.name = name;
this.productionTime = productionTime;
}
// 做任务
public void doTask() {
try {
TimeUnit.SECONDS.sleep(this.productionTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(this.name + " 已做完");
}
}
第一种写法:
@Slf4j(topic = "c.TestCompletableFuture_doTask")
public class TestCompletableFuture_doTask {
public static void main(String[] args) {
log.debug("该二手台式机可用处理器数量:{}", Runtime.getRuntime().availableProcessors());
log.debug("当前线程池中的最大线程数:{}", ForkJoinPool.getCommonPoolParallelism());
log.debug("开始");
long startTime = System.currentTimeMillis();
// 创建任务
List<Task> tasks = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
Task task = new Task("任务" + i, 1);
tasks.add(task);
}
// 做任务
List<CompletableFuture> completableFutureList = new ArrayList<>();
for (Task task : tasks) {
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> task.doTask());
// 将所有任务加到 CompletableFuture 集合中
completableFutureList.add(cf);
}
// 等待 CompletableFuture 集合中的所有任务执行完毕
CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[completableFutureList.size()])).join();
log.debug("做完所有任务的耗时:{}", (System.currentTimeMillis() - startTime));
}
}
00:50:41.392 c.TestCompletableFuture_doTask [main] - 该二手台式机可用处理器数量:4
00:50:41.392 c.TestCompletableFuture_doTask [main] - 当前线程池中的最大线程数:3
00:50:41.397 c.TestCompletableFuture_doTask [main] - 开始
00:50:42.467 c.Task [ForkJoinPool.commonPool-worker-3] - 任务3 已做完
00:50:42.467 c.Task [ForkJoinPool.commonPool-worker-2] - 任务2 已做完
00:50:42.467 c.Task [ForkJoinPool.commonPool-worker-1] - 任务1 已做完
00:50:42.467 c.TestCompletableFuture_doTask [main] - 做完所有任务的耗时:1069
第二种写法(用Stream简化代码,结果还是一样,主要是简化代码):
@Slf4j(topic = "c.TestCompletableFuture_doTask")
public class TestCompletableFuture_doTask {
public static void main(String[] args) {
log.debug("该二手台式机可用处理器数量:{}", Runtime.getRuntime().availableProcessors());
log.debug("当前线程池中的最大线程数:{}", ForkJoinPool.getCommonPoolParallelism());
log.debug("开始");
long startTime = System.currentTimeMillis();
// 将创建的任务加到 CompletableFuture 数组中 并执行
CompletableFuture[] tasks= IntStream.rangeClosed(1, 3)
.mapToObj(i -> new Task("任务" + i, 1))
.map(task -> CompletableFuture.runAsync(task::doTask))
.toArray(CompletableFuture[]::new);
// 等待 CompletableFuture 数组中的所有任务执行完
CompletableFuture.allOf(tasks).join();
log.debug("做完所有任务的耗时:{}", (System.currentTimeMillis() - startTime));
}
}
00:51:13.655 c.TestCompletableFuture_doTask [main] - 该二手台式机可用处理器数量:4
00:51:13.655 c.TestCompletableFuture_doTask [main] - 当前线程池中的最大线程数:3
00:51:13.667 c.TestCompletableFuture_doTask [main] - 开始
00:51:14.896 c.Task [ForkJoinPool.commonPool-worker-2] - 任务2 已做完
00:51:14.896 c.Task [ForkJoinPool.commonPool-worker-1] - 任务1 已做完
00:51:14.896 c.Task [ForkJoinPool.commonPool-worker-3] - 任务3 已做完
00:51:14.896 c.TestCompletableFuture_doTask [main] - 做完所有任务的耗时:1229
测试 任务数 超过 CompletableFuture 线程池的最大线程数:
@Slf4j(topic = "c.TestCompletableFuture_doTask")
public class TestCompletableFuture_doTask {
public static void main(String[] args) {
log.debug("该二手台式机可用处理器数量:{}", Runtime.getRuntime().availableProcessors());
log.debug("当前线程池中的最大线程数:{}", ForkJoinPool.getCommonPoolParallelism());
log.debug("开始");
long startTime = System.currentTimeMillis();
// 将创建的任务加到 CompletableFuture 数组中 并执行
CompletableFuture[] tasks= IntStream.rangeClosed(1, 3)
.mapToObj(i -> new Task("任务" + i, 1))
.map(task -> CompletableFuture.runAsync(task::doTask))
.toArray(CompletableFuture[]::new);
// 等待 CompletableFuture 数组中的所有任务执行完
CompletableFuture.allOf(tasks).join();
log.debug("做完所有任务的耗时:{}", (System.currentTimeMillis() - startTime));
}
}
01:06:31.516 c.TestCompletableFuture_doTask [main] - 该二手台式机可用处理器数量:4
01:06:31.516 c.TestCompletableFuture_doTask [main] - 当前线程池中的最大线程数:3
01:06:31.527 c.TestCompletableFuture_doTask [main] - 开始
01:06:32.636 c.Task [ForkJoinPool.commonPool-worker-2] - 任务2 已做完
01:06:32.636 c.Task [ForkJoinPool.commonPool-worker-1] - 任务1 已做完
01:06:32.637 c.Task [ForkJoinPool.commonPool-worker-3] - 任务3 已做完
01:06:33.637 c.Task [ForkJoinPool.commonPool-worker-2] - 任务4 已做完
01:06:33.637 c.TestCompletableFuture_doTask [main] - 做完所有任务的耗时:2110
CompletableFuture 配合 自定义线程池 使用
@Slf4j(topic = "c.TestCompletableFuture_doTask")
public class TestCompletableFuture_doTask {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
log.debug("开始");
long startTime = System.currentTimeMillis();
// 将创建的任务加到 CompletableFuture 数组中 并执行
CompletableFuture[] tasks= IntStream.rangeClosed(1, 3)
.mapToObj(i -> new Task("任务" + i, 1))
.map(task -> CompletableFuture.runAsync(task::doTask, pool)) // 传入自定义线程池
.toArray(CompletableFuture[]::new);
// 等待 CompletableFuture 数组中的所有任务执行完
CompletableFuture.allOf(tasks).join();
log.debug("做完所有任务的耗时:{}", (System.currentTimeMillis() - startTime));
pool.shutdown();
}
}
01:32:25.794 c.TestCompletableFuture_doTask [main] - 开始
01:32:26.871 c.Task [pool-1-thread-10] - 任务10 已做完
01:32:26.872 c.Task [pool-1-thread-9] - 任务9 已做完
01:32:26.872 c.Task [pool-1-thread-8] - 任务8 已做完
01:32:26.872 c.Task [pool-1-thread-7] - 任务7 已做完
01:32:26.872 c.Task [pool-1-thread-6] - 任务6 已做完
01:32:26.873 c.Task [pool-1-thread-5] - 任务5 已做完
01:32:26.873 c.Task [pool-1-thread-4] - 任务4 已做完
01:32:26.873 c.Task [pool-1-thread-3] - 任务3 已做完
01:32:26.874 c.Task [pool-1-thread-2] - 任务2 已做完
01:32:26.874 c.Task [pool-1-thread-1] - 任务1 已做完
01:32:26.874 c.TestCompletableFuture_doTask [main] - 做完所有任务的耗时:1080
可以看到就算做10个任务,耗时也是1s左右,但不是任何数量的任务都只耗时1s
一台计算机,一瞬间处理的最大任务数量跟CPU的处理能力有关,也跟内存、硬盘、网卡等设备有关
具体跟什么有关,取决于任务本身所需要的资源
由于测试案例中的任务使用sleep模拟耗时的,但是sleep这个操作不太占CPU资源,
所以当传入自定义线程池后,任务数超过了CPU核心数后,耗时也不多