Future和Callable、FutureTask实现,带有返回值的线程请求

2022-07-19 12:26:21

通过ExecutorService.submit()方法提交的任务,可以获取任务执行完的返回值。


在实际业务场景中,Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果。
1、Callable接口类似于Runnable,只是Runnable没有返回值。
2、Callable任务除了返回正常结果之外,如果发生异常,该异常也会被返回,即Future可以拿到异步执行任务各种结果;
3、Future.get方法会导致主线程阻塞,直到Callable任务执行完成;

submit实现


通过submit方法提交的Callable任务会被封装成了一个FutureTask对象。

FutureTask


1、FutureTask在不同阶段拥有不同的状态state,初始化为NEW;
2、FutureTask类实现了Runnable接口,这样就可以通过Executor.execute方法提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法;

FutureTask.get实现


内部通过awaitDone方法对主线程进行阻塞,具体实现如下:


1、如果主线程被中断,则抛出中断异常;
2、判断FutureTask当前的state,如果大于COMPLETING,说明任务已经执行完成,则直接返回;
3、如果当前state等于COMPLETING,说明任务已经执行完,这时主线程只需通过yield方法让出cpu资源,等待state变成NORMAL;
4、通过WaitNode类封装当前线程,并通过UNSAFE添加到waiters链表;
5、最终通过LockSupport的park或parkNanos挂起线程;

FutureTask.run实现


FutureTask.run方法是在线程池中被执行的,而非主线程
1、通过执行Callable任务的call方法;
2、如果call执行成功,则通过set方法保存结果;
3、如果call执行有异常,则通过setException保存异常;

set

setException

set和setException方法中,都会通过UnSAFE修改FutureTask的状态,并执行finishCompletion方法通知主线程任务已经执行完成;

finishCompletion

1、执行FutureTask类的get方法时,会把主线程封装成WaitNode节点并保存在waiters链表中;
2、FutureTask任务执行完成后,通过UNSAFE设置waiters的值,并通过LockSupport类unpark方法唤醒主线程;


最后来一个Future、Callable、FutureTask调用区别实例
class Task implements Callable<String> {
        @Override
        public String call() throws Exception {
            TimeUnit.SECONDS.sleep(8);
            return Thread.currentThread().getName()+" Callable is call";
        }
    }

    public void show() {
        Task mTask=new Task();
        //线程池调用Future和Callable
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        Future<String> future = executorService.submit(mTask);
        System.out.println("ExecutorSevice and Future and Callable is doing");
        try {
            String resultOne = future.get();
            System.out.println("resultOne值为:" + resultOne);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //线程池调用FutureTask
        FutureTask<String> futureTask=new FutureTask<String>(mTask);
        executorService.submit(futureTask);
        System.out.println("ExecutorSevice and FutureTask is doing");
        try {
            String resultTwo = futureTask.get();
            System.out.println("resultTwo值为:" + resultTwo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //Thread调用FutureTask
        FutureTask<String> futureTaskTwo=new FutureTask<String>(mTask);
        new Thread(futureTaskTwo).start();
        System.out.println("Thread and FutureTask is doing");
        try {
            String resultThree = futureTaskTwo.get();
            System.out.println("resultThree值为:" + resultThree);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

日志打印如下:

  • 作者:itzilong
  • 原文链接:https://blog.csdn.net/zhizhuodewo6/article/details/77897752
    更新时间:2022-07-19 12:26:21