本文主要是介绍CompletableFuture的基本使用方法,在后面一篇文章中会写一个简单的demo。
这种情况通常我们会在计算的开始阶段使用它。
CompletableFuture cf = CompletableFuture.completedFuture("message"); // 创建一个预定义结果
assertTrue(cf.isDone()); // 是否完成
assertEquals("message", cf.getNow(null)); // 结果比对
cf.getNow(null)
如果任务完成则获得返回值,如果调用时未完成则返回设置的默认值(null)
thenApply 该方法将返回一个新的CompletionStage,并且将操作函数的返回值作为泛型参数
long main_thread_id = Thread.currentThread().getId();
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> {
assertEquals(main_thread_id, Thread.currentThread().getId());
assertFalse(Thread.currentThread().isDaemon());
return s.toUpperCase(); // 此处返回String 所以泛型为String
});
assertEquals("MESSAGE", cf.getNow(null));
thenApplyAsync 与 thenApply 区别就是 前者将会异步的执行任务
CompletableFuture的方法中 Async 后缀的均为异步操作
CompletableFuture在异步执行任务的时候,不指定Executor的情况下,异步执行通过 ForkJoinPool 实现
异步操作的时候,我们使用 join 来等待任务完成
long main_thread_id = Thread.currentThread().getId();
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
assertNotEquals(main_thread_id, Thread.currentThread().getId()); //由于异步了 所以与主线程id不一致
// 异步执行通过ForkJoinPool实现, 它使用守护线程去执行任务
assertTrue(Thread.currentThread().isDaemon());
return s.toUpperCase();
});
assertNull(cf.getNow(null)); // 此时任务未完成返回null
assertEquals("MESSAGE", cf.join()); // 通过join等待返回结果
执行任务方法都可以使用指定的Executor来执行操作
ExecutorService executorService = Executors.newFixedThreadPool(3, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "HHH");
}
});
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
assertEquals("HHH", Thread.currentThread().getName()); // 使用指定线程池内线程执行
assertFalse(Thread.currentThread().isDaemon()); // 此时非守护进程执行
return s.toUpperCase();
}, executorService); // 填入 指定线程池 executorService
assertNull(cf.getNow(null));
assertEquals("MESSAGE", cf.join()); // 通过join等待返回结果
下一阶段接收了当前阶段的结果,如果不需要使用返回值时,可以使用 thenAccept
StringBuffer result = new StringBuffer();
// 此时不存在返回结果 所以不需要用泛型
CompletableFuture cf = CompletableFuture.completedFuture("message").thenAcceptAsync(result::append);
assertEquals("此时result长度为0", 0, result.length());
cf.join(); // 异步需要等待执行完成
assertEquals("此时result长度为7", 7, result.length());
我们使用 handle 来定义出现以异常时的的处理方式,这个处理操作也是可以异步的 handleAsync
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
int a = 1 / 0; // 发生异常
return s;
});
// 如果在异步的时候需要通知CompletableFuture 发生了异常 可以使用 cf.completeExceptionally(e)
// 如果发生异常 则返回 发生了异常
CompletableFuture exceptionHandler = cf.handle((s, th) -> (th != null) ? "发生了异常" : "");
try {
cf.join();
fail("此处不会被执行");
} catch (CompletionException ex) { // just for testing
assertEquals("/ by zero", ex.getCause().getMessage()); // 不能除以0异常
}
assertEquals("发生了异常", exceptionHandler.join());
我们也可以在 whenComplete 来处理异常,这个处理操作也是可以异步的 whenCompleteAsync
whenComplete 操作需要接收两个参数 ,第一个参数为返回值 第二个为异常信息
CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
int a = 1 / 0; // 发生异常
return s;
}).whenComplete((v,th)->{
assertNotEquals(null,th); // 产生了异常
});
CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase).whenComplete((v,th)->{
assertNull(th); // 未产生异常
assertEquals("MESSAGE",v);
});
通过调用 cancel 来取消任务 ,或者使用 completeExceptionally(new CancellationException())
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
fail("任务被取消此段不执行");
return s;
});
CompletableFuture cf2 = cf.exceptionally(e -> "取消任务");
cf.cancel(true); // 取消任务
//cf.completeExceptionally(new CancellationException()); // 效果等同
assertTrue(cf.isCompletedExceptionally()); // 异常中断
assertEquals("取消任务", cf2.join());
applyToEither 只要有一个执行完成 则终止另外一个 如果同时执行完成,使用当前任务返回结果,而不是applyToEither方法中指定的任务的返回结果
String original = "Message";
CompletableFuture cf1 = CompletableFuture.completedFuture(original)
.thenApplyAsync(s -> {
try {
Thread.sleep(1000); // 延时 测试效果
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前任务执行");
return s.toUpperCase();
});
/*
applyToEither
只要有一个执行完成 则终止另外一个 如果同时执行完成 使用当前返回结果
*/
CompletableFuture cf2 = cf1.applyToEither(
CompletableFuture.completedFuture(original).thenApplyAsync(s -> {
System.out.println("指定任务执行");
return s.toLowerCase();
}),
s -> s + " from applyToEither");
String result = cf2.join();
System.out.println(result);
assertTrue(result.endsWith(" from applyToEither"));
acceptEither 与 applyToEither 区别就在于 前者无返回值类型
String original = "Message";
StringBuilder result = new StringBuilder();
CompletableFuture cf = CompletableFuture.completedFuture(original)
.thenApplyAsync(s -> {
System.out.println("当前任务执行");
return s.toUpperCase();
})
.acceptEither(CompletableFuture.completedFuture(original).thenApplyAsync(s -> {
System.out.println("指定任务执行");
return s.toLowerCase();
}),
s -> result.append(s).append("from acceptEither"));
cf.join();
assertTrue(result.toString().endsWith("from acceptEither"));
runAfterBoth 无返回值 当前任务和指定任务都完成时,才执行指定操作。
String original = "Message";
StringBuilder result = new StringBuilder();
CompletableFuture.completedFuture(original).thenApply(s -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前任务执行");
return s.toUpperCase();
}).runAfterBoth(
CompletableFuture.completedFuture(original).thenApply(s -> {
System.out.println("指定任务执行");
return s.toLowerCase();
}),
() -> result.append("done"));
System.out.println(original);
assertTrue("Result was empty", result.length() > 0);
thenAcceptBoth 无返回值,该方法将两个任务的返回值作为指定操作的参数
String original = "Message";
StringBuffer res = new StringBuffer();
CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).thenAcceptBoth(
CompletableFuture.completedFuture(original).thenApply(String::toLowerCase),
(s, s2) -> {
res.append(s).append(s2);
}
);
assertEquals("MESSAGEmessage", res.toString());
thenCombine 有返回值 ,该方法将两个任务的返回值作为指定操作的参数
String original = "Message";
CompletableFuture res = CompletableFuture.completedFuture(original)
.thenApply(String::toUpperCase)
.thenCombine(
CompletableFuture.completedFuture(original)
.thenApply(String::toLowerCase),
(s, s2) -> s + s2);
assertEquals("MESSAGEmessage", res.getNow(null));
thenCompose 有返回值 ,该方法将当前任务的返回值 作为指定操作的参数
String original = "Message";
CompletableFuture res = CompletableFuture.completedFuture(original)
.thenApply(String::toUpperCase)
.thenCompose(
s -> CompletableFuture.completedFuture(original)
.thenApply(String::toLowerCase)
.thenApply(s2 -> s + s2));
assertEquals("MESSAGEmessage", res.getNow(null));
anyOf 有返回值,如果有一个任务完成(包括异常) 则整个任务完成
StringBuilder result = new StringBuilder();
List messages = Arrays.asList("a", "b", "c");
CompletableFuture.anyOf(messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApply(String::toUpperCase))
.toArray(CompletableFuture[]::new))
.whenComplete((res, th) -> {
if (th == null) {
assertTrue(isUpperCase(((String) res).charAt(0)));
result.append(res);
}
});
assertEquals(result.length(), 1);
StringBuilder result_except = new StringBuilder();
CompletableFuture> cf = CompletableFuture.anyOf(messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApply(s -> {
if (s.equals("a")) {
int a = 1 / 0;
}
return s.toUpperCase();
}))
.toArray(CompletableFuture>[]::new))
.whenComplete((res, th) -> {
if (th == null) {
assertFalse(isUpperCase(((String) res).charAt(0)));
result_except.append(res);
}
});
CompletableFuture exceptionHandler = cf.handle((s, th) -> (th != null) ? "发生了异常" : "");
assertEquals(result_except.length(), 0);
assertEquals(exceptionHandler.join(), "发生了异常");
allOf 所有任务完成在执行操作
List messages = Arrays.asList("a", "b", "c");
StringBuilder result = new StringBuilder();
List> futures = messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApply(String::toUpperCase))
.collect(Collectors.toList());
long main_id = Thread.currentThread().getId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.whenComplete((v, th) -> {
assertEquals(main_id,Thread.currentThread().getId());
if (th == null) { // 未发生异常
futures.forEach(cf -> assertTrue(isUpperCase(cf.getNow(null).charAt(0))));
result.append("done");
}
});
assertEquals("done", result.toString());
List messages = Arrays.asList("a", "b", "c");
StringBuilder result = new StringBuilder();
List> futures = messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApplyAsync(s -> {
try {
Thread.sleep(1000); // 如果此处没有延时 allof的完成操作将不是异步的
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}))
.collect(Collectors.toList());
CompletableFuture cf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.whenComplete((v, th) -> {
System.out.println(Thread.currentThread().getName());
futures.forEach(f -> assertTrue(isUpperCase(f.getNow(null).charAt(0))));
result.append("done");
});
assertEquals(0, result.length());
cf.join();
assertEquals("done", result.toString());
在测试 异步的 allOf 的时候发现,JVM 会对任务是否异步进行优化 。
如果执行任务时间短暂且当前线程不繁忙,那么任务将会同步执行
下面贴上测试代码 不知道大家是否也是一样的结果
// 此时任务无延时
public void test18() {
int count = 0; // 记录异步次数
for (int i = 0; i < 1000; i++) {
if (test_allof_no_dealy()) count++;
}
System.out.println("出现异步次数:" + count);
}
public boolean test_allof_no_dealy() {
List messages = Arrays.asList("a", "b", "c");
StringBuilder result = new StringBuilder();
List> futures = messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApplyAsync(String::toUpperCase))
.collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.whenComplete((v, th) -> {
assertFalse(Thread.currentThread().isDaemon()); // 主线程执行
futures.forEach(f -> assertTrue(isUpperCase(f.getNow(null).charAt(0))));
result.append("done");
});
if (result.length() == 0) return true; // 此时异步
return false; // 同步
}
多次执行结果:
出现异步次数:512
出现异步次数:483
// 此时任务延时0.001s
public void test19() {
int count = 0; // 记录异步次数
for (int i = 0; i < 1000; i++) {
if (test_allof_dealy()) count++;
}
System.out.println("出现异步次数:" + count);
}
public boolean test_allof_dealy() {
List messages = Arrays.asList("a", "b", "c");
StringBuilder result = new StringBuilder();
List> futures = messages.stream()
.map(msg -> CompletableFuture.completedFuture(msg)
.thenApplyAsync(s -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s.toUpperCase();
}))
.collect(Collectors.toList());
CompletableFuture cf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.whenComplete((v, th) -> {
futures.forEach(f -> assertTrue(isUpperCase(f.getNow(null).charAt(0))));
result.append("done");
});
if (result.length() == 0) return true; // 此时异步
return false; // 同步
}
多次执行结果:
出现异步次数:1000
出现异步次数:1000