美文网首页
Callable和FutureTask

Callable和FutureTask

作者: SilenceDut | 来源:发表于2016-07-18 21:27 被阅读284次

    Callable

    Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。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;
    }
    

    通过Executors的静态函数callable(Runnable task,...)可将Runnable转换为Callable类型,该适配函数的实现如下 :

     public static  Callable callable(Runnable task, T result) { 
        if (task == null) throw new NullPointerException(); 
        return new RunnableAdapter(task, result); 
    }
    

    RunnableAdapter适配器

    static final class  RunnableAdapter implements Callable { 
        final Runnable task; final T result;     
        RunnableAdapter(Runnable task, T result) { 
            this.task = task;
            this.result = result;
        } 
        public T call() { 
            task.run(); 
            return result;
       } 
    }
    

    暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。

    Future

    Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作get方法会阻塞,直到任务返回结果。Future声明如下 :

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

    FutureTask

    FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了Futrue这两个接口,

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

    另外它还可以包装Runnable和Callable, 由构造函数注入依赖。

    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
     }
    

    使用

    那么怎么使用这些类呢呢?一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:

    1. <T> Future<T> submit(Callable<T> task);
    2. <T> Future<T> submit(Runnable task, T result);
    3. Future<?> submit(Runnable task);

    第一个submit方法里面的参数类型就是Callable,
    第二个和第三个是可以看到,Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。
    并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。因此FutureTask既是Future、
    Runnable,又是包装了Callable( 如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。因为一般FutureTask是在Executor中执行,但Executor只能执行Runnable,所以将Callable进行了封装。
    由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。运用示例代码如下:

    /** * Created by SilenceDut on 16/7/18. */
    public class FutureTest {    
        public static void main(String[] args) {                
            FutureTest futureTest = new FutureTest();            
            futureTest.useExecutor();            
            futureTest.useThread();  
        }    
        private void useExecutor() {        
            SumTask sumTask = new SumTask(1000);                
            ExecutorService executor =   
            Executors.newCachedThreadPool();            
            FutureTask<Integer> futureTask = new   
            FutureTask<Integer>(sumTask);            
            executor.submit(futureTask);        
            executor.shutdown();       
            try {            
                System.out.println(Thread.currentThread().getName()+"useExecutor运行结果" + futureTask.get());        
            } catch (InterruptedException e) {            
                e.printStackTrace();      
            } catch (ExecutionException e) {            
                e.printStackTrace();       
            }    
        }   
        private void useThread() {        
            SumTask sumTask = new SumTask(500);          
            FutureTask<Integer> futureTask = new FutureTask<Integer>(sumTask) {    
                @Override    
                protected void done() {        
                    super.done();        
                    try {            
                      // 这是在后台线程  
                      System.out.println(Thread.currentThread().getName()+"useThread运行结果" + get());        
                    } catch (InterruptedException e) {            
                        e.printStackTrace();        
                    } catch (ExecutionException e) {            
                        e.printStackTrace();        
                    }    
               }
            };    
            Thread thread = new Thread(futureTask);       
            thread.start();       
            try {            
                //这是在主线程,会阻塞 
                System.out.println(Thread.currentThread().getName()+"useThread运行结果" + futureTask.get());    
            } catch (InterruptedException e) {            
                e.printStackTrace();       
            } catch (ExecutionException e) {            
                e.printStackTrace();       
            }    
        }        
      class SumTask implements Callable<Integer> {        
          int number;        
          public SumTask(int num) {            
              this.number = num;      
          }        
          @Override       
          public Integer call() throws Exception {            
              System.out.println(Thread.currentThread().getName());            
              Thread.sleep(5000);            
              int sum = 0;            
              for (int i = 0; i < number; i++) {                
                  sum += i;            
              }           
              return sum;        
          }    
       }
    }
    

    结果:

    pool-1-thread-1
    main::useExecutor运行结果499500
    Thread-0
    main::useThread运行结果124750
    Thread-0::useThread运行结果124750
    

    参考《Android进阶开发—从小工到专家》

    相关文章

      网友评论

          本文标题:Callable和FutureTask

          本文链接:https://www.haomeiwen.com/subject/wyfmjttx.html