Callable、Future接口实现原理,FutureTask 原理解析,获取线程的返回值

callable

callbale只是一个接口,用来处理执行一个线程后可以获取到线程的返回值,这个是主要的用途

public interface Callable<V> {
    V call() throws Exception;
}

从上面看这个接口非常的简单,仅仅是执行一个返回,然后有个返回值,这个在线程中的实现原理是什么样的?返回值是怎么处理的?
其实就是让某个线程中有个callable接口的实例,然后在调用call这个方法,将返回值储存起来,在某个时候去调用。由于为了方便我们,
java的类库中已经很好的实现了这个逻辑,那么我们就来聊聊。

Future接口(用来处理线程执行时的状态,可以取消,可以获取执行的返回值)

V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(…)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(…)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:
(1)能够中断执行中的任务
(2)判断任务是否执行完成
(3)获取任务执行完成后额结果。

public interface Future<V> {  
    boolean cancel(boolean mayInterruptIfRunning);  
    boolean isCancelled();  
    boolean isDone();  
    V get() throws InterruptedException, ExecutionException;  
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;  
}  

这里写图片描述
Future接口的实现类实现了Runable和Future的方法,可以看做为一个Runable可以直接扔到线程池中去执行,主要看看FutureTask的实现类的成员变量和run方法的实现

   //状态的转换
    /* NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

    /** The underlying callable; nulled out after running */
    private Callable<V> callable;//执行callable的子类的实例
    /** The result to return or exception to throw from get() */

    //返回值
    private Object outcome; // non-volatile, protected by state reads/writes
    /** The thread running the callable; CASed during run() */

    //当前执行的线程的引用,用来取消或者中断当前的线程
    private volatile Thread runner;

    //调用get的堆栈线程
    /** Treiber stack of waiting threads */
    private volatile WaitNode waiters;

   public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    //执行Runable 伪造一个返回值,就是你传递进去的...
    public FutureTask(Runnable runnable, V result) {
            this.callable = Executors.callable(runnable, result);
            this.state = NEW;       // ensure visibility of callable
    }

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);//如果有异常保存下来,get的时候在扔给你....
                }
                if (ran)
                    set(result);//这里执行完了会调用finishCompletion,会将所有的阻塞的返回!
            }
        } 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);
        }
    }

小小实践

  • callable实现类
package Thread;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

/**
 * descrption: 实现Callable接口将线程执行后的结果返回
 * authohr: wangji
 * date: 2017-09-01 15:21
 */
@Slf4j
public class ComputeTask implements Callable<Integer> {
    private Integer result = 0;
    private String taskName = "";

    public ComputeTask(Integer iniResult, String taskName){
        result = iniResult;
        this.taskName = taskName;
    }
    public Integer call() throws Exception {
          return todoWork();
    }
    public Integer todoWork() {
        log.info("子线程计算任务: "+taskName+" 开始执行!");
        for (int i = 0; i < 100; i++) {
            result =i+result;
        }
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
           log.error("线程被中断",e);
        }
        log.info("子线程计算任务: "+taskName+" 执行完成! 结果:"+result);
        return result;
    }
    public String getTaskName(){
        return this.taskName;
    }
}
  • 测试类
    测试类中,首先创建了一个线程池,然后创建了一堆Callable,然后接受返回值,一个个的等待
package Thread;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * descrption: 测试执行线程的返回值
 * authohr: wangji
 * date: 2017-09-01 15:27
 */
@Slf4j
public class CallableTest {

    public static void main(String[] args) {
        //1. create a thread pool
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //2 create a list of Callable
        List<Future<Integer>> returnFutureList = new ArrayList<Future<Integer>>();
        for(int i=0;i<20;i++){
            //ComputeTask implement callbale interface
             ComputeTask callableItem = new ComputeTask(30+i,"work"+i);
             Future<Integer> future = executorService.submit(callableItem);
             returnFutureList.add(future);
        }
        log.info("提交完了任务,可以把其他的事情做完了,再来轮询获取线程返回的结果的信息");
        for(int i=0;i<returnFutureList.size();i++){
            Future<Integer> future =null;
            try {
                 future = returnFutureList.get(i);
                 //依次阻塞一直等待获取到结果的信息
                 Integer taskReturnValue = future.get();
            } catch (InterruptedException e) {
                log.error("当前线程中断",e);
                Thread.currentThread().interrupt();//重新声明线程中断了
                if(future !=null){
                    future.cancel(true);
                }

            } catch (ExecutionException e) {
                log.error("执行线程异常",e);
                if(future !=null){
                    future.cancel(true);
                }
            }
        }

    }
}
2017-09-01 15:52:23,799  INFO [ComputeTask.java:25] : 子线程计算任务: work0 开始执行!
2017-09-01 15:52:23,799  INFO [CallableTest.java:31] : 提交完了任务,可以把其他的事情做完了,再来轮询获取线程返回的结果的信息
2017-09-01 15:52:23,799  INFO [ComputeTask.java:25] : 子线程计算任务: work4 开始执行!
2017-09-01 15:52:23,799  INFO [ComputeTask.java:25] : 子线程计算任务: work3 开始执行!
2017-09-01 15:52:23,799  INFO [ComputeTask.java:25] : 子线程计算任务: work2 开始执行!
2017-09-01 15:52:23,799  INFO [ComputeTask.java:25] : 子线程计算任务: work1 开始执行!
2017-09-01 15:52:28,801  INFO [ComputeTask.java:34] : 子线程计算任务: work0 执行完成! 结果:4980
2017-09-01 15:52:28,802  INFO [ComputeTask.java:25] : 子线程计算任务: work5 开始执行!
2017-09-01 15:52:28,803  INFO [ComputeTask.java:34] : 子线程计算任务: work4 执行完成! 结果:4984
2017-09-01 15:52:28,803  INFO [ComputeTask.java:34] : 子线程计算任务: work1 执行完成! 结果:4981
2017-09-01 15:52:28,803  INFO [ComputeTask.java:34] : 子线程计算任务: work3 执行完成! 结果:4983
2017-09-01 15:52:28,803  INFO [ComputeTask.java:34] : 子线程计算任务: work2 执行完成! 结果:4982
2017-09-01 15:52:28,804  INFO [ComputeTask.java:25] : 子线程计算任务: work8 开始执行!
2017-09-01 15:52:28,804  INFO [ComputeTask.java:25] : 子线程计算任务: work7 开始执行!
2017-09-01 15:52:28,803  INFO [ComputeTask.java:25] : 子线程计算任务: work6 开始执行!
2017-09-01 15:52:28,805  INFO [ComputeTask.java:25] : 子线程计算任务: work9 开始执行!
2017-09-01 15:52:33,803  INFO [ComputeTask.java:34] : 子线程计算任务: work5 执行完成! 结果:4985
2017-09-01 15:52:33,804  INFO [ComputeTask.java:25] : 子线程计算任务: work10 开始执行!
2017-09-01 15:52:33,807  INFO [ComputeTask.java:34] : 子线程计算任务: work8 执行完成! 结果:4988
2017-09-01 15:52:33,807  INFO [ComputeTask.java:34] : 子线程计算任务: work7 执行完成! 结果:4987
2017-09-01 15:52:33,808  INFO [ComputeTask.java:34] : 子线程计算任务: work6 执行完成! 结果:4986
2017-09-01 15:52:33,807  INFO [ComputeTask.java:25] : 子线程计算任务: work11 开始执行!
2017-09-01 15:52:33,808  INFO [ComputeTask.java:25] : 子线程计算任务: work13 开始执行!
2017-09-01 15:52:33,808  INFO [ComputeTask.java:25] : 子线程计算任务: work12 开始执行!
2017-09-01 15:52:33,812  INFO [ComputeTask.java:34] : 子线程计算任务: work9 执行完成! 结果:4989
2017-09-01 15:52:33,812  INFO [ComputeTask.java:25] : 子线程计算任务: work14 开始执行!
2017-09-01 15:52:38,804  INFO [ComputeTask.java:34] : 子线程计算任务: work10 执行完成! 结果:4990
2017-09-01 15:52:38,805  INFO [ComputeTask.java:25] : 子线程计算任务: work15 开始执行!
2017-09-01 15:52:38,809  INFO [ComputeTask.java:34] : 子线程计算任务: work13 执行完成! 结果:4993
2017-09-01 15:52:38,809  INFO [ComputeTask.java:34] : 子线程计算任务: work11 执行完成! 结果:4991
2017-09-01 15:52:38,810  INFO [ComputeTask.java:34] : 子线程计算任务: work12 执行完成! 结果:4992
2017-09-01 15:52:38,809  INFO [ComputeTask.java:25] : 子线程计算任务: work16 开始执行!
2017-09-01 15:52:38,810  INFO [ComputeTask.java:25] : 子线程计算任务: work18 开始执行!
2017-09-01 15:52:38,810  INFO [ComputeTask.java:25] : 子线程计算任务: work17 开始执行!
2017-09-01 15:52:38,813  INFO [ComputeTask.java:34] : 子线程计算任务: work14 执行完成! 结果:4994
2017-09-01 15:52:38,813  INFO [ComputeTask.java:25] : 子线程计算任务: work19 开始执行!
2017-09-01 15:52:43,806  INFO [ComputeTask.java:34] : 子线程计算任务: work15 执行完成! 结果:4995
2017-09-01 15:52:43,812  INFO [ComputeTask.java:34] : 子线程计算任务: work16 执行完成! 结果:4996
2017-09-01 15:52:43,813  INFO [ComputeTask.java:34] : 子线程计算任务: work17 执行完成! 结果:4997
2017-09-01 15:52:43,813  INFO [ComputeTask.java:34] : 子线程计算任务: work18 执行完成! 结果:4998
2017-09-01 15:52:43,815  INFO [ComputeTask.java:34] : 子线程计算任务: work19 执行完成! 结果:4999

实现原理:主要是线程池实现了这几个接口,间接的使用了FutureTask(FutureTaks 实现了Runable所以可以直接调用void execute(Runnable command);)

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

看线程池的内部的实现

  //AbstractExecutorService
  public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

看这个下面的看懂了吧!new 了一个FutureTask,ftask本身实现了Runable所以就很直接了,运行线程的结果,就保存在了FutureTask的实例中啦!

//AbstractExecutorService
 protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);

  }

缺陷

上面这个测试的缺陷非常的明显,需要一个个的执行等待,即使先执行完成的也不能首先获取得到他的返回的值,有一种解决方案
ExecutorCompletionService,将Executor和BlockingQueue功能融合在一起
[http://blog.csdn.net/lmj623565791/article/details/27250059](带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll)

[http://blog.csdn.net/u010185262/article/details/55255452](FutureTask 讲解的不错)

http://huangyunbin.iteye.com/blog/1942369

http://www.cnblogs.com/Mainz/p/3546347.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值