Java并发编程-扩展可回调的Future

本文探讨了如何扩展Java的Future接口以支持回调功能。通过分析Future的实现原理,作者创建了一个子接口,增加了回调功能。文章介绍了编码实现、测试过程,并总结了在并发编程中使用适配器模式和接口扩展的重要性。
摘要由CSDN通过智能技术生成

 

前提#

最近在看JUC线程池java.util.concurrent.ThreadPoolExecutor的源码实现,其中了解到java.util.concurrent.Future的实现原理。从目前java.util.concurrent.Future的实现来看,虽然实现了异步提交任务,但是任务结果的获取过程需要主动调用Future#get()或者Future#get(long timeout, TimeUnit unit),而前者是阻塞的,后者在异步任务执行时间不确定的情况下有可能需要进行轮询,这两种情况和异步调用的初衷有点相违背。于是笔者想结合目前了解到的Future实现原理的前提下扩展出支持(监听)回调的Future,思路上参考了Guava增强的ListenableFuture。本文编写的时候使用的JDK是JDK11,其他版本可能不适合。

简单分析Future的实现原理#

虚拟例子推演#

并发大师Doug Lea在设计JUC线程池的时候,提供了一个顶层执行器接口Executor

public interface Executor {

    void execute(Runnable command);
}    

实际上,这里定义的方法Executor#execute()是整套线程池体系最核心的接口,也就是ThreadPoolExecutor定义的核心线程、额外创建的线程(线程池最大线程容量 - 核心线程数)都是在这个接口提交任务的时候懒创建的,也就是说ExecutorService接口扩展的功能都是基于Executor#execute()的基础进行扩展。Executor#execute()方法只是单纯地把任务实例Runnable对象投放到线程池中分配合适的线程执行,但是由于方法返回值是void类型,我们是无法感知任务什么时候执行完毕。这个时候就需要对Runnable任务实例进行包装(下面是伪代码 + 伪逻辑):

// 下面这个Wrapper和Status类是笔者虚构出来
@RequiredArgsConstructor
class Wrapper implements Runnable{

    private final Runnable target;
    private Status status = Status.of("初始化");

    @Override
    public void run(){
        try{
           target.run();
           status = Status.of("执行成功");
        }catch(Throwable t){
           status = Status.of("执行异常"); 
        }
    }
}

我们只需要把new Wrapper(原始Runnable实例)投放到线程池执行,那么通过定义好的Status状态记录变量就能得知异步任务执行的状态,以及什么时候执行完毕(包括正常的执行完毕和异常的执行完毕)。这里仅仅解决了任务执行的状态获取,但是Executor#execute()方法法返回值是void类型的特点使得我们无法回调Runnable对象执行的结果。这个时候需要定义一个可以回调执行结果的接口,其实已经有现成的接口Callable

@FunctionalInterface
public interface Callable<V> {

    V call() throws Exception;
}    

这里遇到了一个问题:由于Executor#execute()只接收Runnable参数,我们需要把Callable接口适配到Runnable接口,这个时候,做一次简单的委托即可:

@RequiredArgsConstructor
class Wrapper implements Runnable{

    private final Callable callable;
    private Status status = Status.of("初始化");
    @Getter
    private Object outcome;

    @Override
    public void run(){
        try{
           outcome = callable.call();
           status = Status.of("执行成功");
        }catch(Throwable t){
           status = Status.of("执行异常"); 
           outcome = t;
        }
    }
}

这里把Callable实例直接委托给Wrapper,而Wrapper实现了Runnable接口,执行结果直接存放在定义好的Object类型的对象outcome中即可。当我们感知到执行状态已经结束ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾听铃的声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值