Java 并发编程——Callable+Future+FutureTask

 

项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现。

 

复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AddTask implements Callable {

    private int a,b;

    public AddTask(int a, int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public Integer call() throws Exception {
        Integer result = a + b;
        return result;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        //JDK目前为止返回的都是FutureTask的实例  
        Future future = executor.submit(new AddTask(1, 2));
        Integer result = future.get();// 只有当future的状态是已完成时(future.isDone() = true),get()方法才会返回  
    }
}
复制代码

 

Callable接口                                                                                                     

Callable接口Runable接口可谓是兄弟关系,只不过Callable是带返回值的。

复制代码
public interface Callable {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
复制代码

 

Future 接口                                                                                                        

接口函数及含义 :public interface Future

 boolean  cancel(boolean mayInterruptIfRunning)

取消当前执行的任务,如果已经执行完毕或者已经被取消/由于某种原因不能被取消 则取消任务失败。

参数mayInterruptIfRunning: 当任务正在执行,如果参数为true ,则尝试中断任务,否则让任务继续执行知道结束。

 
boolean isCancelled()
Returns {@code true} if this task was cancelled before it completed
* normally.
 
  
boolean isDone();
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
 
  

V get() throws InterruptedException, ExecutionException;

/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
由注释可以看出,当没有执行完成时,需要等待任务执行完成了才会将计算结果返回。

 

V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;

Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.

如果等待的时间超过设置的时间则会报 TimeoutException异常

FutureTask                                                                                                     

public class FutureTask implements RunnableFuture

由定义可以看出它实现了RunnableFuture接口,那么这个接口又是什么呢?看下面的接口定义,其实很简单

复制代码
public interface RunnableFuture extends Runnable, Future {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}
复制代码

再回到FutureTask,它其实就是实现了Runnable和Future接口,FutureTask的执行是 状态转换的过程,源码中有七种状态如下:

复制代码
  * Possible state transitions:
     * 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;
复制代码

当FutureTask刚刚被创建时,它的状态是NEW,其它状态查看源码。

其它成员变量:

复制代码
 /** The underlying callable; nulled out after running */
    private 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;
    /** Treiber stack of waiting threads */
    private volatile WaitNode waiters;
复制代码

callable是待执行的任务,FutureTask 的 run()函数中执行callable中的任务。

outcome : 是callable的执行结果,当正常执行完成后会将结果set到outcome中

runner:是执行callable 的线程

WaitNode : 是的受阻塞的线程链表,当cancel一个任务后,阻塞的线程会被唤醒。

 

构造函数:

复制代码
public FutureTask(Callable callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
复制代码

从构造函数可以看出,不光可以通过callable构造FutureTask还可以通过Runnable接口转化为callable来构造。关键函数为黄色标记部分,Executors中的实现源码如下:

复制代码
/**
     * A callable that runs given task and returns given result.
     */
    private static final class RunnableAdapter implements Callable {
        private final Runnable task;
        private final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
复制代码

这里面不懂result到底有什么意义,明明就是预先设置好的。

 

其它具体的方法说明这里不再细说,里面用到了很多sun.misc.Unsafe中的方法以及其他SDK底层接口,后续有时间再学习。下面贴出了整个源码及说明

  View Code

FutureTask简单应用:

复制代码
public class FutureMain {
    public static void main(String[] args)
            throws ExecutionException, InterruptedException {
        //构造FutureTask
        FutureTask futureTask = new FutureTask(new CallableClass("xxx"));
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //执行FutureTask,发送请求
        //在这里开启线程进行RealData的call()执行
        executorService.submit(futureTask);

        System.out.println("请求完毕。。。");
        try {
            //这里可以进行其他额外的操作,这里用sleep代替其他业务的处理
            Thread.sleep(200);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        //获取call()方法的返回值
        //如果此时call()方法没有执行完成,则依然会等待
        System.out.println("真实数据:"+futureTask.get());
    }
}
复制代码

 www.kzo4326.cn
www.tso8557.cn
www.nwm1536.cn
www.tae4138.cn
www.dxc3579.cn
www.ffp5727.cn
www.lhb4836.cn
www.xdi0113.cn
www.bpa2365.cn
www.fks8445.cn
www.aht8537.cn
www.cun5054.cn
www.gdk7028.cn
www.ypk8666.cn
www.wan2959.cn
www.sit9945.cn
www.zmj4226.cn
www.ccn6233.cn
www.jck8045.cn
www.ckk6213.cn
www.mak1390.cn
www.vii0197.cn
www.pwj5001.cn
www.wvh4263.cn
www.mvg0339.cn
www.yif9712.cn
www.jta0960.cn
www.omx8816.cn
www.nlc4773.cn
www.dep9137.cn
www.vlq7732.cn
www.umg2515.cn
www.kog1435.cn
www.nxf9936.cn
www.hqh7518.cn
www.hij5984.cn
www.vui9639.cn
www.fzl7156.cn
www.wue0833.cn
www.dye6768.cn
www.ryh7899.cn
www.lij0467.cn
www.epv8502.cn
www.lru8400.cn
www.mtr5072.cn
www.kbs9896.cn
www.qfk7654.cn
www.myb6827.cn
www.tcr0461.cn
www.xua4102.cn
www.tzn6024.cn
www.kme4313.cn
www.bnb6875.cn
www.yio4898.cn
www.yat8046.cn

 

 

你可能感兴趣的:(Java 并发编程——Callable+Future+FutureTask)