美文网首页
Java多线程--Future及FutureTask

Java多线程--Future及FutureTask

作者: Qi0907 | 来源:发表于2017-03-21 11:38 被阅读0次

    1、Future
    线程是异步的,所以不可能直接从别的线程中得到函数返回值。Futrue可以监视目标线程调用call的情况,当调用Future的get()方法获得结果时,当前线程就开始阻塞,直接call方法结束返回结果
    任务提交给Future,由Future控制Executor来完成这个任务。一段时间后,可以从Future那儿取出结果。
    Future接口是Future<V>,其中V代表了Future执行的任务返回值的类型。

    Future接口的方法介绍:
    boolean cancel (boolean mayInterruptIfRunning)
    取消任务的执行。参数指定是否立即中断任务,或者等待一会结束
    boolean isCancelled ()
    任务是否已经取消,任务正常完成前将其取消,则返回true
    boolean isDone ()
    任务是否已经完成。如果任务正常终止、异常或取消,都将返回true
    V get () throws InterruptedException, ExecutionException
    等待任务执行结束,然后获得V类型的结果。InterruptedException线程被中断的异常,ExecutionException任务执行的异常,如果任务被取消,还会抛出CancellationException
    V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
    同上面的get功能一样,多了设置超时时间。超时,将抛出TimeoutException

    下面是一个使用Future计算Fibonacci数列的demo
    通过future.get()取得Callable的返回结果,用于后面的计算

    import java.util.Random;
    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 Future20170322 {
        static int f0 = 1;
        static int f1 = 1;
        static int f2 = 0;
        
        public static void main(String[] args) {
            ExecutorService threadPool = Executors.newSingleThreadExecutor();
    
            for(int i=2; i<10; i++) {
                Future<Integer> future = threadPool.submit(new Callable<Integer>() {
                    public Integer call() throws Exception {
                        return f0 + f1;
                    }
                });
                try {
                    f2 = future.get();
                    f0 = f1;
                    f1 = f2;
                    System.out.println(f2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    2、FutureTask
    为什么要使用FutureTask?
    Future可以通过Future.get()来取得计算结果。但是,若开启了多个任务,就不知道哪个任务最先结束。因此,若要实现 “当某任务结束时,立刻做某些事情”这一功能,就需要写一些额外的代码

    package FutureTask20170329;
    
    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.FutureTask;
    
    public class FutureTask20170329 { 
        
        public static void main(String[] args) {  
            ExecutorService executor = Executors.newCachedThreadPool();  
            //循环创建5个任务,并把他放到FutureTask中
            for(int i=0; i<5; i++) {
                Callable<String> c = new Task();  
                MyFutureTask ft = new MyFutureTask(c);  
                executor.submit(ft);  
            }  
            executor.shutdown();  
        }  
              
    }  
      
    class MyFutureTask extends FutureTask<String> {  
      
        public MyFutureTask(Callable<String> callable) {  
            super(callable);  
        }  
      
        //回调函数,当任务完成时就会被出发
        @Override  
        protected void done() {  
            try {  
                System.out.println(get() + " 线程执行完毕!");  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            } catch (ExecutionException  e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
          
          
    }  
      
    //创建一个任务,随机睡眠10s之内
    class Task implements Callable<String> {  
      
        public String call() throws Exception {  
            Random rand = new Random();  
            Thread.sleep(rand.nextInt(10));  
            return Thread.currentThread().getName();  
        }  
    } 
    

    执行结果:


    Paste_Image.png

    从结果可以看出,每个线程执行完毕都会知道,所以可以在其中加入任务完毕之后所需的操作。
    使用遍历的方式虽然也可以解决取得多任务结果的问题,但却不是最优的效果,FutureTask正是为此而存在,它有一个回调函数protected void done(),当任务结束时,该回调函数会被触发。因此,只需重载该函数,即可实现在线程刚结束时就做某些事情

    相关文章

      网友评论

          本文标题:Java多线程--Future及FutureTask

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