FutureTask+Callable+ExecutorService实现异步返回值源码

上文中,我们说了ExecutorService运行Runnable和Callable的原理

使用代码例子

package My.ThreadExcutorService;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import net.sf.json.JSONObject;
import java.util.concurrent.*;
/**
 * @author ddd
 * @create 2021-06-10    19:17
 **/
public class Main
{
    public static void main(String[] args) throws InterruptedException, ExecutionException{
        Thread.sleep(1000);
        // Future是接口,FutureTask是具体实现
        FutureTask<JSONObject> futureTask=new FutureTask<JSONObject>(new MyRun1());
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
        //创建线程池
        ExecutorService exc = new ThreadPoolExecutor(20, 20, 30000,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), namedThreadFactory);

        System.out.println(" ----------开始运行 ");
        exc.submit(futureTask);
        System.out.println(" ----------运行结束 ");
        // 获得返回值
        try{
            // 最大等大时间,若提前结束呢?  答,若提前结束即不会等待最长时间
            JSONObject returnobject=(JSONObject)futureTask.get(20,TimeUnit.SECONDS);
            System.out.println("returnobject.get(\"message\") = " + returnobject.get("message"));
        }
        catch (TimeoutException e){
            futureTask.cancel(true);// 中断执行此任务的线程
            System.out.println(" 超时,线程取消! ");
        }
        catch (InterruptedException e) {
            System.out.println("线程中断出错。");
            futureTask.cancel(true);// 中断执行此任务的线程
        } catch (ExecutionException e) {
            System.out.println("线程服务出错。");
            futureTask.cancel(true);// 中断执行此任务的线程
        }
        finally {
            System.out.println(" 测试结束 ");
            //  线程池不会自动关闭,不关闭程序就不会结束
            //这种不关闭就不会结束的语句一定写的finally中,即使出异常也不会有问题
            exc.shutdown();
        }

    }
}

package My.ThreadExcutorService;

import net.sf.json.JSONObject;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
/**
 * @author ddd
 * @create 2021-06-10    17:12
 **/
public class MyRun1 implements Callable<JSONObject> {
    private List<JSONObject> reList = null;
    
    @Override
    public JSONObject call() throws Exception {
        JSONObject map = JSONObject.fromObject("{}");
        System.out.println("MyRun1 正在运行");
        Thread.sleep(1000);
        System.out.println("MyRun1 运行结束");
        map.put("message","MyRun1");
        return map;
    }
}

FutureTask各接口依赖关系

在这里插入图片描述
我们可以看到FutureTask是实现了Runnable接口的,所以可以被开辟线程运行,那它是怎么运行Callable的呢
上文我们可以知道,ExecutorService的submit()传入Callable,最终也是通过executor方法调用Thread.start()方法来运行的,那Thread.start()的本质又是运行Runnable的run()方法,所以我们来看FutureTask的run()方法

FutureTask的run()方法

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    **result = c.call();**
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    **set(result);**
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

其中我们可以看到在FutureTask的run()方法中调用了传入的Callable实现类的call()方法
并用result保存了返回值,调用了set()方法保存返回值

FutureTask的set()方法保存返回值

protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

set()方法将返回值保存到了outcome变量中,可以通过get()方法获取

FutureTask的get()方法获取返回值

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

    /**
     * @throws CancellationException {@inheritDoc}
     */
    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }

有一个等待最大时间参数和无参get()方法,其中都会判断线程当前的运行状态再去决定是否可以返回值,未到完成状态则会等待,达到COMPLETING 状态则通过report()函数返回值

    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

线程定义了七种状态

    private volatile int state;
    private static final int NEW          = 0;// 新建=0;
    private static final int COMPLETING   = 1;// 完成=1;
    private static final int NORMAL       = 2;// 正常=2;
    private static final int EXCEPTIONAL  = 3;// 异常=3;
    private static final int CANCELLED    = 4;// 取消=4;
    private static final int INTERRUPTING = 5;// 中断中=5;
    private static final int INTERRUPTED  = 6;// 已中断=6;

总结

1)FutureTask实现了RunnableFuture、Runnable和Future;

2)ExecutorService最终通过new Thread(new Runnable()).start()的形式运行run()

3)FutureTask重写了Runnable的run(),在其中调用了Callable的call()方法,并用set(result)存储返回值到outcome变量

4)FutureTask通过get方法获取outcome(Object)对象值,从而成功拿到线程执行的返回值;

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值