代码改变世界

Callable,Future,FutureTask

2017-07-16 10:05  ttylinux  阅读(234)  评论(0编辑  收藏  举报
1.概念定义
2.实现例子
3.总结
 
1.概念定义
 
1.Callable
Callable是一个接口,效果类似Runnable接口。实现该接口,然后,耗时操作在call()方法中执行。与Runnable接口不同的是,call方法需要返回执行的结果。
public interface Callable<V>{
  V call() throws Exception;
}

public interface Runnable{
  void run();
}
View Code
2.Future
A Future represents the result of an asynchronous(异步的) computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. Cancellation is performed by the cancel method. Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled. If you would like to use a Future for the sake of cancellability but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task.
Future是一个接口,实现这个接口的对象具备的特征,可以取消任务,获取任务的结果,判断任务的执行状态。Future就是对具体的Callable任务或者Runnable任务执行取消,获取结果,获取当前状态。
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;
}
View Code
3.FutureTask
A cancellable asynchronous computation. This class provides a base implementation of Future, with methods to start and cancel a computation, query to see if the computation is complete, and retrieve the result of the computation. The result can only be retrieved when the computation has completed; the get methods will block if the computation has not yet completed. Once the computation has completed, the computation cannot be restarted or cancelled (unless the computation is invoked using runAndReset()).
A FutureTask can be used to wrap a Callable or Runnable object. Because FutureTask implements Runnable, a FutureTask can be submitted to an Executor for execution.
In addition to serving as a standalone class, this class provides protected functionality that may be useful when creating customized task classes.
FutureTask实现了Future接口,实现了Runnable接口。那么,它就是一个Runnable对象,Future对象。它的run方法就是执行耗时的操作。
应用:
//创建FutureTask对象,传入Callable对象;Callable对象,耗时操作是放在call方法里面的
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskExample {
       
       public static void main(String[] args) {
             
             
             Callable<String> worker = new Callable<String>() {
                    
                    @Override
                    public String call() throws Exception {
                           // TODO Auto-generated method stub
                           System.out.println("do computation");
                           return "computation result";
                    }
             } ;
             
             
             FutureTask<String> future = new FutureTask<String>(worker) {
                    @Override
                    protected void  done() {
                           
                       System.out.println("Done task");     
                    }
             };
             
             new Thread(future) {
                    
                    @Override
                    public void run() {
                           future.run();
                    }
                    
             }.start();
             
             try {
                    System.out.println("computation:"+future.get());
             } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
}
View Code

调用FutureTask的run方法就触发执行,可以查看FutureTask的源码得到解释:调用run,会导致调用sync.innerRun();而innerRun会调用传入的Callable对象的call方法:

public class FutureTask<V> implements RunnableFuture<V> {


    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        sync = new Sync(callable);
    }

.....
    // The following (duplicated) doc comment can be removed once
    //
    // 6270645: Javadoc comments should be inherited from most derived
    //          superinterface or superclass
    // is fixed.
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    public void run() {
        sync.innerRun();
    }

    /**
     * Synchronization control for FutureTask. Note that this must be
     * a non-static inner class in order to invoke the protected
     * <tt>done</tt> method. For clarity, all inner class support
     * methods are same as outer, prefixed with "inner".
     *
     * Uses AQS sync state to represent run status
     */
    private final class Sync extends AbstractQueuedSynchronizer {
    
           void innerRun() {
            if (!compareAndSetState(READY, RUNNING))
                return;

            runner = Thread.currentThread();
            if (getState() == RUNNING) { // recheck after setting thread
                V result;
                try {
                    result = callable.call();
                } catch (Throwable ex) {
                    setException(ex);
                    return;
                }
                set(result);
            } else {
                releaseShared(0); // cancel
            }
        }

    }

}
View Code

 

2.实现例子

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskExample {
       
       public static void main(String[] args) {
             
             
             Callable<String> worker = new Callable<String>() {
                    
                    @Override
                    public String call() throws Exception {
                           // TODO Auto-generated method stub
                           System.out.println("do computation");
                           return "computation result";
                    }
             } ;
             
             
             FutureTask<String> future = new FutureTask<String>(worker) {
                    @Override
                    protected void  done() {
                           
                       System.out.println("Done task");     
                    }
             };
             
             new Thread(future) {
                    
                    @Override
                    public void run() {
                           future.run();
                    }
                    
             }.start();
             
             try {
                    System.out.println("computation:"+future.get());
             } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
}
View Code

 

3.总结

1.FutureTask就是一个Runnable对象,也是一个Future对象。
2.使用FutureTask要使用Callable对象
3.最终的耗时操作,计算是在Callable对象的call方法中执行
4.使用FutureTask是为了获得Future接口定义的特性,可以获得一个任务的执行状态,执行结果,可以取消任务的执行。这都是Runnable对象不具备的特性,Thread对象也不具备这些特性。