在多线程中,用于执行异步任务时候可以使用实现Runable接口,或是实现Callable接口,并进行使用线程池提交任务。
Runnable:线程无返回值
Callable:线程可进行带有返回值
使用Runnable接口:
private static void runnable() {
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 没有返回值
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread() + ":" +123);
}
};
//submit是ExecutorService的接口,execute是Executor的接口。
//submit有返回值,future;execute没有返回值
//submit能够捕获异常,通过get。
Future<?> submit = executorService.submit(runnable);
executorService.execute(runnable);
}
使用Callable接口,返回的参数通过Future来保存:
private static void callable() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "使用callable接口";
}
};
Future<String> submit = executorService.submit(callable);
String s = submit.get();
System.out.println(s);
}
CompleteFuture
单future执行
相当于上面实例中使用executorService.submit()进行调用,常用方法:
runAsync():异步进行执行方法,不带有返回值,可以传入自定义线程池;可见run方法入参传入为Runnable接口用于执行不带出参的线程,只返回CompletableFuture
supplyAsync():异步执行方法,带有返回值,可以传入自定义线程池;可见supply方法传入的为Supplier接口用于生产带有出参结果的CompletableFuture
get():用于获取结果,如果有异常会进行抛出异常
getNow():getNow如果计算完成或异常了则会返回结果或者异常,如果在调用getNow时候线程未完成时候,则返回getNow中的值。
private static void completableFuture() throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture.runAsync(() -> System.out.println(Thread.currentThread() + "runAsync无返回值执行"));
CompletableFuture.runAsync(() -> System.out.println(Thread.currentThread() +"runAsync无返回值自定义线程池执行"),executorService);
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值执行");
return "supplyAsync有返回值执行";
});
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
return "supplyAsync有返回值自定义线程池执行";
},executorService);
Thread.sleep(500);
//get方法用于获取返回结果,如果有异常会进行抛出异常
String s = supplyAsync1.get();
//getNow如果计算完成或异常了则会返回结果或者异常,如果在调用getNow时候线程未完成时候,则返回getNow中的值。
String now = supplyAsync2.getNow("默认值");
System.out.println("supplyAsync2返回值:" + now);
}
控制台输出内容:
Connected to the target VM, address: '127.0.0.1:0', transport: 'socket'
Thread[ForkJoinPool.commonPool-worker-1,5,main]runAsync无返回值执行
Thread[pool-1-thread-1,5,main]runAsync无返回值自定义线程池执行
Thread[ForkJoinPool.commonPool-worker-1,5,main]supplyAsync有返回值执行
Thread[pool-1-thread-2,5,main]supplyAsync有返回值自定义线程池执行
supplyAsync2返回值:supplyAsync有返回值自定义线程池执行
Disconnected from the target VM, address: '127.0.0.1:0', transport: 'socket'
单一流程性执行
流程性表示当前任务处理完成后完成另外一个任务,前后存在依赖性。
thenApply()
thenApplyAsync()
thenAccept()
thenAcceptAsync()
thenRun()
thenRunAsync()类似的方法还有很多,流程性的方法均有两个,一个是带有Async结尾的,说明是异步的,同时异步是支持传入自定义线程池的,不带有Async说明是同步的,同步的话当前线程进行执行。
thenApply()/thenApplyAsync():方法支持传入上一个结果作为入参,并且返回一个带有出参的CompletableFuture;可见apply方法的入参为Function接口
thenAccept()/thenAcceptAsync():方法支持传入入参,但是不返回出参;可见accept方法入参为Consumer接口
thenRun()/thenRunAsync():方法既不需要入参也不需要出参;可见入参为Runnable接口
thenCompose()/thenComposeAsync():方法在某一个流程后可以在继续新建一个future,然后将future进行返回
留一个疑问:thenComposeAsync 和 thenApplyAsync 有什么区别?
private static void completableFuture1() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
return "我的名字叫汤姆";
},executorService);
supplyAsync1.thenApplyAsync((result) -> {
System.out.println(Thread.currentThread() + "thenApply有返回值自定义线程池执行,收到的参数:"+result);
return "姓名:汤姆,年龄:22";
},executorService).thenAcceptAsync(result -> System.out.println(Thread.currentThread() + "thenAcceptAsync无返回值自定义线程池执行,收到的参数:"+result)
,executorService).thenRunAsync(()-> System.out.println(Thread.currentThread() + "thenRunAsync运行,汤姆体检完毕"),executorService);
CompletableFuture<String> thenComposeAsync = supplyAsync1.thenComposeAsync(s -> CompletableFuture.supplyAsync(
() -> {
System.out.println(Thread.currentThread() + "收到信息:" + s);
System.out.println(Thread.currentThread() + "保姆开始体检");
return "保姆体检完成";
},executorService
));
String s = thenComposeAsync.get();
System.out.println(s);
}
组合流程性执行
组合流程性执行是指可以将两个future进行组合,共同判断是否满足情况继续向后执行下一个任务
thenCombine()、thenCombineAsync()、thenAcceptBoth、thenAcceptBothAsync(),runAfterBoth、runAfterBothAsync()、thenCompose(),thenComposeAsync(),同样和单一流程中的描述一样:一个是带有Async结尾的,说明是异步的,同时异步是支持传入自定义线程池的,不带有Async说明是同步的,同步的话当前线程进行执行。
thenCombine()/thenCombineAsync():方法将两个任务的结果传递到下一个任务的作为入参,并且带有返回值;
thenAcceptBoth/thenAcceptBothAsync():方法将两个任务的结果传递到下一个任务作为入参,不带有返回值;
runAfterBoth()/runAfterBothAsync():方法既不需要入参也不需要返回值,在两个任务执行完进行下一个任务执行。
private static void completableFuture2() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
return "汤姆开始体检";
},executorService);
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
return "杰瑞开始体检";
},executorService);
CompletableFuture<String> thenCombineAsync = supplyAsync1.thenCombineAsync(supplyAsync2, (tom, jerry) -> {
System.out.println(Thread.currentThread() + "thenCombineAsync收到第一个信息:" + tom);
System.out.println(Thread.currentThread() + "thenCombineAsync收到第二个信息:" + jerry);
return "汤姆和杰瑞都完成了体检";
}, executorService);
CompletableFuture<Void> thenAcceptBothAsync = supplyAsync1.thenAcceptBothAsync(supplyAsync2, (tom, jerry) -> {
System.out.println(Thread.currentThread() + "thenAcceptBothAsync收到第一个信息:" + tom);
System.out.println(Thread.currentThread() + "thenAcceptBothAsync收到第二个信息:" + jerry);
}, executorService);
CompletableFuture<Void> runAfterBothAsync = supplyAsync1.runAfterBothAsync(supplyAsync2, ()-> {
System.out.println(Thread.currentThread() + "两个人都体检完成了");
}, executorService);
}
处理异常情况
whenCompleteAsync(),handleAsync(),exceptionally()用于处理结果和异常的方法
whenCompleteAsync()和handleAsync()接受参数为任务的处理结果和异常信息,前者不返回出参,后者返回出参,exceptionally()只接受异常结果,但是使用时前置任务节点必须要有返回值形式。
handleAsync():失败成功时候都会获取返回的结果。
exceptionally():只有异常的时候返回返回结果。
下面这段代码有点长,但很丰富
private static void completableFuture3() throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
return "汤姆开始体检";
},executorService);
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread() + "supplyAsync有返回值自定义线程池执行");
throw new RuntimeException("杰瑞体检失败啦");
},executorService);
/*
whenCompleteAsync
*/
CompletableFuture<String> whenCompleteAsync1 = supplyAsync1.whenCompleteAsync((result, exception) -> {
System.out.println(Thread.currentThread()+"whenCompleteAsync1收到成功结果:"+result);
});
CompletableFuture<String> whenCompleteAsync2 = supplyAsync2.whenCompleteAsync((result, exception) -> {
System.out.println(Thread.currentThread()+"whenCompleteAsync2收到成功结果:"+result);
if(exception!=null){
System.out.println("whenCompleteAsync2收到了异常");
// exception.printStackTrace();
}
});
Thread.sleep(500);
System.out.println("whenCompleteAsync1:" + whenCompleteAsync1.get());
//此处get也会进行返回错误栈信息,由于whenCompleteAsync不带有返回参数,此处get仍会返回异常信息
// System.out.println("whenCompleteAsync2:" + whenCompleteAsync2.get());
/*
handleAsync:无论成功失败都会返回结果
*/
CompletableFuture<String> handleAsync1 = supplyAsync1.handleAsync((result, exception) -> {
System.out.println(Thread.currentThread() + "handleAsync1收到成功结果:" + result);
return "chenggongla";
});
CompletableFuture<String> handleAsync2 = supplyAsync2.handleAsync((result, exception) -> {
System.out.println(Thread.currentThread() + "handleAsync2收到成功结果:" + result);
if(exception!=null){
System.out.println("handleAsync2收到了异常");
// exception.printStackTrace();
}
return "shibaila";
});
System.out.println("handleAsync1:"+handleAsync1.get());
System.out.println("handleAsync2:"+handleAsync2.get());
/*
exceptionally 仅当有异常的时候才会返回信息,其余情况为前任务的返回值
*/
CompletableFuture<String> exceptionally1 = supplyAsync1.exceptionally((exception) -> {
System.out.println(Thread.currentThread() + "exceptionally1收到成功结果:exception=" + exception == null);
return "成功啦";
});
CompletableFuture<String> exceptionally2 = supplyAsync2.exceptionally((exception) -> {
System.out.println(Thread.currentThread() + "exceptionally1收到成功结果:exception=" + exception == null);
return "失败啦";
});
String s = exceptionally2.get();
System.out.println("exceptionally1:"+exceptionally1.get());
System.out.println("exceptionally2:"+s);
}
控制台输出:
Connected to the target VM, address: '127.0.0.1:0', transport: 'socket'
Thread[pool-1-thread-1,5,main]supplyAsync有返回值自定义线程池执行
Thread[pool-1-thread-2,5,main]supplyAsync有返回值自定义线程池执行
Thread[ForkJoinPool.commonPool-worker-1,5,main]whenCompleteAsync1收到成功结果:汤姆开始体检
Thread[ForkJoinPool.commonPool-worker-1,5,main]whenCompleteAsync2收到成功结果:null
whenCompleteAsync2收到了异常
whenCompleteAsync1:汤姆开始体检
Thread[ForkJoinPool.commonPool-worker-3,5,main]handleAsync1收到成功结果:汤姆开始体检
handleAsync1:chenggongla
Thread[ForkJoinPool.commonPool-worker-3,5,main]handleAsync2收到成功结果:null
handleAsync2收到了异常
handleAsync2:shibaila
false
exceptionally1:汤姆开始体检
exceptionally2:失败啦
其他
带有either后缀的方法,表示谁先完成就消费谁。allOf()和anyOf()代表所有都完成,和任意也给完成