Java8新的异步编程方式CompletableFuture实现
一.Future
JDK5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。
Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。
Future的接口很简单,只有五个方法。
publicinterfaceFuture{ booleancancel(booleanmayInterruptIfRunning); booleanisCancelled(); booleanisDone(); Vget()throwsInterruptedException,ExecutionException; Vget(longtimeout,TimeUnitunit) throwsInterruptedException,ExecutionException,TimeoutException; }
Future接口的方法介绍如下:
- booleancancel(booleanmayInterruptIfRunning)取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
- booleanisCancelled()任务是否已经取消,任务正常完成前将其取消,则返回true
- booleanisDone()任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
- Vget()throwsInterruptedException,ExecutionException等待任务执行结束,然后获得V类型的结果。InterruptedException线程被中断异常,ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
- Vget(longtimeout,TimeUnitunit)throwsInterruptedException,ExecutionException,TimeoutException同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException
一般情况下,我们会结合Callable和Future一起使用,通过ExecutorService的submit方法执行Callable,并返回Future。
ExecutorServiceexecutor=Executors.newCachedThreadPool(); Futurefuture=executor.submit(()->{//Lambda是一个callable,提交后便立即执行,这里返回的是FutureTask实例 System.out.println("runningtask"); Thread.sleep(10000); return"returntask"; }); try{ Thread.sleep(1000); }catch(InterruptedExceptione){ } System.out.println("dosomethingelse");//前面的的Callable在其他线程中运行着,可以做一些其他的事情 try{ System.out.println(future.get());//等待future的执行结果,执行完毕之后打印出来 }catch(InterruptedExceptione){ }catch(ExecutionExceptione){ }finally{ executor.shutdown(); }
比起future.get(),其实更推荐使用get(longtimeout,TimeUnitunit)方法,设置了超时时间可以防止程序无限制的等待future的结果。
二.CompletableFuture介绍
2.1Future模式的缺点
Future虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,我们无法得知Future什么时候完成。
要么使用阻塞,在future.get()的地方等待future返回的结果,这时又变成同步操作。要么使用isDone()轮询地判断Future是否完成,这样会耗费CPU的资源。
2.2CompletableFuture介绍
Netty、Guava分别扩展了Java的Future接口,方便异步编程。
Java8新增的CompletableFuture类正是吸收了所有GoogleGuava中ListenableFuture和SettableFuture的特征,还提供了其它强大的功能,让Java拥有了完整的非阻塞编程模型:Future、Promise和Callback(在Java8之前,只有无Callback的Future)。
CompletableFuture能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。它避免了传统回调最大的问题,那就是能够将控制流分离到不同的事件处理器中。
CompletableFuture弥补了Future模式的缺点。在异步的任务完成后,需要用其结果继续操作时,无需等待。可以直接通过thenAccept、thenApply、thenCompose等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。
三.CompletableFuture特性
3.1CompletableFuture的静态工厂方法
方法名
描述
runAsync(Runnablerunnable)
使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。
runAsync(Runnablerunnable,Executorexecutor)
使用指定的threadpool执行异步代码。
supplyAsync(Suppliersupplier)
使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值
supplyAsync(Suppliersupplier,Executorexecutor)
使用指定的threadpool执行异步代码,异步操作有返回值
runAsync和supplyAsync方法的区别是runAsync返回的CompletableFuture是没有返回值的。
CompletableFuturefuture=CompletableFuture.runAsync(()->{ System.out.println("Hello"); }); try{ future.get(); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); } System.out.println("CompletableFuture");
而supplyAsync返回的CompletableFuture是由返回值的,下面的代码打印了future的返回值。
CompletableFuturefuture=CompletableFuture.supplyAsync(()->"Hello"); try{ System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); } System.out.println("CompletableFuture");
3.2Completable
方法名 | 描述 |
---|---|
complete(Tt) | 完成异步执行,并返回future的结果 |
completeExceptionally(Throwableex) | 异步执行不正常的结束 |
future.get()在等待执行结果时,程序会一直block,如果此时调用complete(Tt)会立即执行。
CompletableFuturefuture=CompletableFuture.supplyAsync(()->"Hello"); future.complete("World"); try{ System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); }
执行结果:
World
可以看到future调用complete(Tt)会立即执行。但是complete(Tt)只能调用一次,后续的重复调用会失效。
如果future已经执行完毕能够返回结果,此时再调用complete(Tt)则会无效。
CompletableFuturefuture=CompletableFuture.supplyAsync(()->"Hello"); try{ Thread.sleep(5000); }catch(InterruptedExceptione){ e.printStackTrace(); } future.complete("World"); try{ System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); }
执行结果:
Hello
如果使用completeExceptionally(Throwableex)则抛出一个异常,而不是一个成功的结果。
CompletableFuturefuture=CompletableFuture.supplyAsync(()->"Hello"); future.completeExceptionally(newException()); try{ System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); }
执行结果:
java.util.concurrent.ExecutionException:java.lang.Exception
...
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。