概述
在Java编程中,经常需要异步执行某个任务,一般继承Thread类或实现Runnable接口的方法来异步执行任务,除了这两种方法外,还可实现Callable来实现,在使用Callable的同时一般都会使用Future来配合获取执行结果,这几种方式使用起来或多或少存在不足,在jdk1.8中,提供了一个异步处理任务的工具CompletableFuture,接下来就通过实际代码体验CompletableFuture的使用。
创建异步线程任务
根据supplier创建CompletableFuture任务
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> System.out.println("hello CompletableFuture1"), executor);
// supplyAsync的使用
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> {
System.out.print("hello ");
return "CompletableFuture2";
}, executor);
// 阻塞等待,runAsync 的future 无返回值,输出null
System.out.println(completableFuture.join());
// 阻塞等待
String name = future.join();
System.out.println(name);
executor.shutdown();
--------输出结果--------
hello CompletableFuture1
null
hello CompletableFuture2
线程串行执行
任务完成则运行action,不关心上一个任务的结果,无返回值
CompletableFuture<Void> future = CompletableFuture
.supplyAsync(() -> "hello siting", executor)
.thenRunAsync(() -> System.out.println("OK"), executor);
executor.shutdown();
--------输出结果--------
OK
任务完成则运行fn,依赖上一个任务的结果,有返回值
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> "hello world", executor)
.thenApplyAsync(data -> {
System.out.println(data); return "OK";
}, executor);
System.out.println(future.join());
executor.shutdown();
--------输出结果--------
hello world
OK
thenCompose - 任务完成则运行fn,依赖上一个任务的结果,有返回值
//第一个异步任务,常量任务
CompletableFuture<String> f = CompletableFuture.completedFuture("OK");
//第二个异步任务
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> "hello world", executor)
.thenComposeAsync(data -> {
System.out.println(data); return f; //使用第一个任务作为返回
}, executor);
System.out.println(future.join());
executor.shutdown();
--------输出结果--------
hello world
OK
线程并行执行
两个CompletableFuture并行执行完,然后执行action,不依赖上两个任务的结果,无返回值
//第一个异步任务,常量任务
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
//第二个异步任务
.supplyAsync(() -> "hello siting", executor)
// () -> System.out.println("OK") 是第三个任务
.runAfterBothAsync(first, () -> System.out.println("OK"), executor);
executor.shutdown();
--------输出结果--------
OK
两个CompletableFuture并行执行完,然后执行action,依赖上两个任务的结果,无返回值
//第一个异步任务,常量任务
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
//第二个异步任务
.supplyAsync(() -> "hello siting", executor)
// (w, s) -> System.out.println(s) 是第三个任务
.thenAcceptBothAsync(first, (s, w) -> System.out.println(s), executor);
executor.shutdown();
--------输出结果--------
hello siting
两个CompletableFuture并行执行完,然后执行fn,依赖上两个任务的结果,有返回值
//第一个异步任务,常量任务
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
//第二个异步任务
.supplyAsync(() -> "hello siting", executor)
// (w, s) -> System.out.println(s) 是第三个任务
.thenCombineAsync(first, (s, w) -> {
System.out.println(s);
return "OK";
}, executor);
System.out.println(future.join());
executor.shutdown();
--------输出结果--------
hello siting
OK
线程并行执行(二者选其最快)
线程并行执行,谁先执行完则谁触发下一任务
上一个任务或者other任务完成, 运行action,不依赖前一任务的结果,无返回值
// 第一个异步任务,休眠1秒,保证最晚执行晚
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
try{ Thread.sleep(1000); }catch (Exception e){}
System.out.println("hello world");
return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
// 第二个异步任务
.supplyAsync(() ->{
System.out.println("hello siting");
return "hello siting";
} , executor)
// () -> System.out.println("OK") 是第三个任务
.runAfterEitherAsync(first, () -> System.out.println("OK") , executor);
executor.shutdown();
--------输出结果--------
hello siting
OK
上一个任务或者other任务完成, 运行action,依赖最先完成任务的结果,无返回值
// 第一个异步任务,休眠1秒,保证最晚执行晚
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
try{ Thread.sleep(1000); }catch (Exception e){}
return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
// 第二个异步任务
.supplyAsync(() -> "hello siting", executor)
// data -> System.out.println(data) 是第三个任务
.acceptEitherAsync(first, data -> System.out.println(data) , executor);
executor.shutdown();
--------输出结果--------
hello siting
上一个任务或者other任务完成, 运行fn,依赖最先完成任务的结果,有返回值
//第一个异步任务,休眠1秒,保证最晚执行晚
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
try{ Thread.sleep(1000); }catch (Exception e){}
return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
//第二个异步任务
.supplyAsync(() -> "hello siting", executor)
// data -> System.out.println(data) 是第三个任务
.applyToEitherAsync(first, data -> {
System.out.println(data);
return "OK";
} , executor);
System.out.println(future);
executor.shutdown();
--------输出结果--------
hello siting
OK
处理任务结果或者异常
exceptionally-处理异常:如果之前的处理环节有异常问题,则会触发exceptionally的调用相当于 try...catch
CompletableFuture<Integer> first = CompletableFuture
.supplyAsync(() -> {
if (true) {
throw new RuntimeException("main error!");
}
return "hello world";
})
.thenApply(data -> 1)
.exceptionally(e -> {
e.printStackTrace(); // 异常捕捉处理,前面两个处理环节的日常都能捕获
return 0;
});
handle-任务完成或者异常时运行fn,返回值为fn的返回
CompletableFuture<Integer> first = CompletableFuture
.supplyAsync(() -> {
if (true) { throw new RuntimeException("main error!"); }
return "hello world";
})
.thenApply(data -> 1)
.handleAsync((data,e) -> {
e.printStackTrace(); // 异常捕捉处理
return data;
});
System.out.println(first.join());
--------输出结果--------
java.util.concurrent.CompletionException: java.lang.RuntimeException: main error!
... 5 more
null
whenComplete-任务完成或者异常时运行action,有返回值
- whenComplete与handle的区别在于,它不参与返回结果的处理,把它当成监听器即可
- 即使异常被处理,在CompletableFuture外层,异常也会再次复现
- 使用whenCompleteAsync时,返回结果则需要考虑多线程操作问题,毕竟会出现两个线程同时操作一个结果
CompletableFuture<AtomicBoolean> first = CompletableFuture
.supplyAsync(() -> {
if (true) { throw new RuntimeException("main error!"); }
return "hello world";
})
.thenApply(data -> new AtomicBoolean(false))
.whenCompleteAsync((data,e) -> {
//异常捕捉处理, 但是异常还是会在外层复现
System.out.println(e.getMessage());
});
first.join();
--------输出结果--------
java.lang.RuntimeException: main error!
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.RuntimeException: main error!
... 5 more
多个任务的简单组合
CompletableFuture<Void> future = CompletableFuture
.allOf(CompletableFuture.completedFuture("A"),
CompletableFuture.completedFuture("B"));
//全部任务都需要执行完
future.join();
CompletableFuture<Object> future2 = CompletableFuture
.anyOf(CompletableFuture.completedFuture("C"),
CompletableFuture.completedFuture("D"));
//其中一个任务行完即可
future2.join();
取消执行线程任务
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (Exception e) { }
return "hello world";
})
.thenApply(data -> 1);
System.out.println("任务取消前:" + future.isCancelled());
// 如果任务未完成,则返回异常,需要对使用exceptionally,handle 对结果处理
future.cancel(true);
System.out.println("任务取消后:" + future.isCancelled());
future = future.exceptionally(e -> {
e.printStackTrace();
return 0;
});
System.out.println(future.join());
--------输出结果--------
任务取消前:false
任务取消后:true
java.util.concurrent.CancellationException
at java.util.concurrent.CompletableFuture.cancel(CompletableFuture.java:2276)
at Test.main(Test.java:25)