美文网首页
Java并发 - Future模式

Java并发 - Future模式

作者: 齐晋 | 来源:发表于2018-12-16 18:02 被阅读39次

    标签:原创 Java 并发

    更多Java并发实战内容,请参考Java并发 - 并发编程实战

    理解Future

    关于Future模式的教程,网上很多,这里就不做详细介绍了。可参考的文章如:

    Future关键点

    这里重点对Future模式的几个关键点做下总结和扩展。

    为什么需要Future

    其实在多线程中,Future的主要作用在于获取执行结果或执行状态。

    当从主线程中启动一个子线程,那么子线程就像一匹脱缰的野马,很难知道什么时候执行完成,什么时候结束。

    如果主线程依赖子线程的结果,由于不知道子线程的执行状态,就可能需要使用彻底理解Java的Future模式所讲的join方式去等待子线程返回结果。这种情况下,主线程会被阻塞,其实跟串行没有什么区别。因此,这种同步等待的方式是不可取的。

    Future模式就是为了实现主线程和子线程同时进行工作,在需要的时候,主线程才去等待子线程结果这种功能。

    就像两个人一起算账,A(假设是主线程)算一部分,B(假设是子线程)算一部分,两个人同时计算自己的部分。当A算完以后,再通过Future.get()方法来获取B计算的结果,最后进行累加。这时,如果B已经算完了,get()方法直接返回结果。如果B还没算完,就等待B算完。

    怎样使用Future

    java concurrent包中的ThreadPoolExecutor中有个sumbmit()方法,返回的就是Future对象:

    public Future<?> submit(Runnable task);
    public <T> Future<T> submit(Runnable task, T result);
    public <T> Future<T> submit(Callable<T> task);
    

    Future有什么缺点?
    Future有个大缺点就是没有办法异步化。也就是说,当子线程的处理结果需要进一步处理时,主线程需要调用get()方法。但是get()方法什么时候调用?这是个很难选择的时间点:可以任何时候调用!

    如果立即调用,get()方法会阻塞主线程,这又成串行执行了!
    如果最后调用,子线程可能早就执行完了,还得保存结果,等待主线程处理!
    计算机程序最浪费时间的操作就是"等待"

    为了避免这种等待,最好使用回调的方式。举个例子:

    主线程发起一个子线程去做一个事情后,继续执行。在主线程不依赖子线程结果的情况下,子线程处理完成后,将处理结果教给另一个线程去做记录。
    这样,所有的线程都不会等待,还完成了各自的工作。

    鉴于JDK Future的缺点,并且解决速度很慢,Guava封装了增强版的Future,供开发者使用

    Guava Future

    guava对Future的增强可参考文章:

    总结起来如下:

    • JDK的Future,guava对应的增强版本是ListenableFuture
    • ListenableFuture增加了void addListener(Runnable listener, Executor executor);方法,可以让子线程在结束的时候,主动调用listener对象,达到异步处理多结果
    • JDK的FutureTask,guava对应的增强版本是ListenableFutureTask
    • JDK的线程池返回的结果只有Future。所以为了支持返回ListenableFuture,guava又封装了一系列的线程池,如:
      • ListeningExecutorService对应JDK的ExecutorService
      • MoreExecutors对应JDK的Executors
    • 还提供了能在调用线程中执行回调的ExecutorService,即 DirectExecutor

    guava增强的使用方法与JDK原生的大同小异

    怎么使用guava Future?
    从上得知,要使用guava的增强,需要使用guava线程池。guava在MoreExecutors中提供了诸多方法,将JDK原生线程池,封装成适合guava体系的线程池,如:

    public static ListeningExecutorService listeningDecorator(ExecutorService delegate);
    
    public static ListeningScheduledExecutorService listeningDecorator(
          ScheduledExecutorService delegate);
    

    JDK8 CompletableFuture

    除了guava扩展了Future,Netty等高性能框架也扩展了Future,可见JDK原生的Future是多么不好用,牛B的程序员已经忍无可忍了。

    JDK做为正统的Java类库,是不是该做点什么。

    终于在JDK8的时候,千呼万唤,出现了CompletableFuture:

    关于CompletableFuture的文章可参考:

    相关文章

      网友评论

          本文标题:Java并发 - Future模式

          本文链接:https://www.haomeiwen.com/subject/qpyxkqtx.html