java Callable与Future

Future模式

Future接口是Java线程Future模式的实现,能够来进行异步计算。html

Future模式能够这样来描述:java

我有一个任务,提交给了Future,Future替我完成这个任务。期间我本身能够去作任何想作的事情。一段时间以后,我就即可以从Future那儿取出结果。并发

就至关于下了一张定货单,一段时间后能够拿着提订单来提货,这期间能够干别的任何事情。其中Future接口就是定货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。dom

 

Callable和Future接口

 

Callable接口

 

Callable和Future一个产生结果,一个拿到结果。异步

Callable接口相似于Runnable,可是Runnable不会返回结果,而Callable能够返回结果,这个返回值能够被Future拿到,也就是说,Future能够拿到异步执行任务的返回值。ide

  •  V call()

 

  1. /** 
  2.  * Computes a result, or throws an exception if unable to do so. 
  3.  * 
  4.  * @return computed result 
  5.  * @throws Exception if unable to compute a result 
  6.  */  
  7. V call() throws Exception;  


 

 

Future接口

Future 表示异步计算的结果。Future接口中有以下方法:ui

  •     boolean cancel(boolean mayInterruptIfRunning)

取消任务的执行。参数指定是否当即中断任务执行,或者等等任务结束this

  •     boolean isCancelled() 

任务是否已经取消,任务正常完成前将其取消,则返回 truespa

  •     boolean isDone()

任务是否已经完成。须要注意的是若是任务正常终止、异常或取消,都将返回true.net

  •     V get()

等待任务执行结束,而后得到V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,若是任务被取消,还会抛出CancellationException

  •     V get(long timeout, TimeUnit unit) 

同上面的get功能同样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。若是计算超时,将抛出TimeoutException
 

Future接口提供方法来检测任务是否被执行完,等待任务执行完得到结果。也能够设置任务执行的超时时间,这个设置超时的方法就是实现Java程序执行超时的关键。

因此,若是须要设定代码执行的最长时间,即超时,能够用Java线程池ExecutorService类配合Future接口来实现。

  1. int result = future.get(5000, TimeUnit.MILLISECONDS);   


 

Future实现类:SwingWorker

 

SwingWorker的用法

http://blog.csdn.net/vking_wang/article/details/8994882 

 

 

 

Future实现类:FutureTask

 

Future的实现类有java.util.concurrent.FutureTask<V>即 javax.swing.SwingWorker<T,V>。一般使用FutureTask来处理咱们的任务。

FutureTask类同时又实现了Runnable接口,因此能够直接提交给Thread、Executor执行。

public class CallableAndFuture {    
    public static void main(String[] args) {    
        Callable<Integer> callable = new Callable<Integer>() {    
            public Integer call() throws Exception {    
                return new Random().nextInt(100);    
            }    
        };   
  
        FutureTask<Integer> future = new FutureTask<Integer>(callable);    
        new Thread(future).start();    
  
        try {    
            Thread.sleep(5000);// 可能作一些事情    
  
            int result = future.get();    
  
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        } catch (ExecutionException e) {    
            e.printStackTrace();    
        }    
    }    
}    

 

经过ExecutorService的submit方法执行Callable,并返回Future

 

使用ExecutorService

 

public class CallableAndFuture {    
    public static void main(String[] args) {   
  
        //ExecutorService.submit()  
        ExecutorService threadPool = Executors.newSingleThreadExecutor();    
        Future<Integer> future = threadPool.submit(new Callable<Integer>() {    
            public Integer call() throws Exception {    
                return new Random().nextInt(100);    
            }    
        });   
  
        try {    
            Thread.sleep(5000);// 可能作一些事情    
  
            int result = future.get(); //Future.get()  
  
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        } catch (ExecutionException e) {    
            e.printStackTrace();    
        }    
    }    
}    

 

若是要执行多个带返回值的任务,并取得多个返回值,可用CompletionService:

CompletionService至关于Executor加上BlockingQueue,使用场景为当子线程并发了一系列的任务之后,主线程须要实时地取回子线程任务的返回值并同时顺序地处理这些返回值,谁先返回就先处理谁。

public class CallableAndFuture {    
    public static void main(String[] args) {    
        ExecutorService threadPool = Executors.newCachedThreadPool();    
        CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);    
        for(int i = 1; i < 5; i++) {    
            final int taskID = i;    
            //CompletionService.submit()  
            cs.submit(new Callable<Integer>() {    
                public Integer call() throws Exception {    
                    return taskID;    
                }    
            });    
        }    
        // 可能作一些事情    
        for(int i = 1; i < 5; i++) {    
            try {    
                int result = cs.take().get();  //CompletionService.take()返回Future  
            } catch (InterruptedException e) {    
                e.printStackTrace();    
            } catch (ExecutionException e) {    
                e.printStackTrace();    
            }    
        }    
    }    
}          

或者不使用CompletionService:先建立一个装Future类型的集合,用Executor提交的任务返回值添加到集合中,最后便利集合取出数据。以下所示:

 

class TaskWithResult implements Callable<String> {  
    private int id;  
  
    public TaskWithResult(int id) {  
        this.id = id;  
    }  
  
    @Override  
    public String call() throws Exception {  
        return "result of TaskWithResult " + id;  
    }  
}  
  
public class CallableTest {  
    public static void main(String[] args) throws InterruptedException,  
            ExecutionException {  
        ExecutorService exec = Executors.newCachedThreadPool();  
        ArrayList<Future<String>> results = new ArrayList<Future<String>>();    //Future 至关因而用来存放Executor执行的结果的一种容器  
        for (int i = 0; i < 10; i++) {  
            results.add(exec.submit(new TaskWithResult(i)));  
        }  
        for (Future<String> fs : results) {  
            if (fs.isDone()) {  
                System.out.println(fs.get());  
            } else {  
                System.out.println("Future result is not yet complete");  
            }  
        }  
        exec.shutdown();  
    }  
}

 

 

区别:

Future集合方法,submit的task不必定是按照加入本身维护的list顺序完成的。从list中遍历的每一个Future对象并不必定处于完成状态,这时调用get()方法就会被阻塞住,若是系统是设计成每一个线程完成后就能根据其结果继续作后面的事,这样对于处于list后面的可是先完成的线程就会增长了额外的等待时间。

而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,若是Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。

因此,先完成的一定先被取出。这样就减小了没必要要的等待时间。

参考文章:

http://www.voidcn.com/blog/vking_wang/article/p-2434628.html

相关文章
相关标签/搜索