美文网首页
每日一结——Future,FutureTask

每日一结——Future,FutureTask

作者: 奔向学霸的路上 | 来源:发表于2020-07-23 09:35 被阅读0次

    Future

    获取任务的执行结果,一般是搭配ExecutorService使用。

    Future接口

    image.png

    获取单个线程的执行结果

    • 调用V Future.get()方法能够阻塞等待执行结果
    • V get(long timeout, TimeUnit unit)方法可以指定等待的超时时间
    // 取消任务
    boolean cancel(boolean mayInterruptIfRunning);
    
    // 获取任务执行结果
    V get() throws InterruptedException, ExecutionException;
    
    // 获取任务执行结果,带有超时时间限制
    V get(long timeout, TimeUnit unit) throws InterruptedException,                             ExecutionException,  TimeoutException;
    
    // 判断任务是否已经取消
    boolean isCancelled();
    
    // 判断任务是否已经结束
    boolean isDone();
    

    FutureTask

    使用场景:

    • 阻塞:Future是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作,get方法会阻塞,直到任务返回结果,也就是说,阻塞。
    • 在高并发环境下确保任务只执行一次(这个嗯。。。我觉得了解一下吧,感觉很牵强)

    FutureTask类图

    FutureTask类图

    从类图可以看出FutureTask即拥有Runnable特性又有Future特性。

    FutureTask方法

    FutureTask方法图

    AQS无非关注点在于:状态(业务主要逻辑控制)、队列(等待队列)、CAS(安全set值)

    FutureTask构造函数

    两个构造函数,入参分别是Runnable、Callable,我们知道Runnable没有返回值,这两个构造函数实际上都是转到Callable来实现返回值。

    /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Runnable}, and arrange that {@code get} will return the
         * given result on successful completion.
         *
         * @param runnable the runnable task
         * @param result the result to return on successful completion. If
         * you don't need a particular result, consider using
         * constructions of the form:
         * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
         * @throws NullPointerException if the runnable is null
         */
        public FutureTask(Runnable runnable, V result) {
            this.callable = Executors.callable(runnable, result);
            this.state = NEW;       // ensure visibility of callable
        }
    
        /**
         * Creates a {@code FutureTask} that will, upon running, execute the
         * given {@code Callable}.
         *
         * @param  callable the callable task
         * @throws NullPointerException if the callable is null
         */
        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }
    
    image.png
    1. Callable执行的方法是call(),Runnable执行的方法是run()。其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,或者交给ExecuteService执行,而Callable则一般都是提交给ExecuteService来执行。
    2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
    3. call方法可以抛出异常,run方法不可以
    4. 运行Callable任务可以拿到一个Future对象,表示异步计算的结果,而且拿到的这个Future对象后,如果调用get()方法,当前线程会阻塞,直到此Callable的call方法执行完毕。

    举例一(由Thread执行):

        public static void main(String[] args) {
            CountSum countSum = new CountSum();// 创建一个Callable对象
            FutureTask<Integer> futureTask = new FutureTask<>(countSum);// 创建FutureTask对象
            Thread thread = new Thread(futureTask);// 开启线程
            thread.start();
            try {
                int sum = futureTask.get();
                System.out.println("主线程获得求和结果:" + sum);
            } catch (Exception e) {
                e.printStackTrace();
                futureTask.cancel(true);
            }
        }
    
        static class CountSum implements Callable<Integer> {
    
            @Override
            public Integer call() throws Exception {
                System.out.println("开始求和");
                int sum = 0;
                for (int i = 0; i < 10000; i++) {
                    sum += i;
                }
                Thread.sleep(2000);
                System.out.println("求和结束");
                return sum;
            }
    
        }
    

    执行结果:

    开始求和
    求和结束
    主线程获得求和结果:49995000
    

    举例二(Futuretask也可以使用ExecutorService执行)

    public static void main(String[] args) {
            CountSum countSum = new CountSum();// 创建一个Callable对象
            FutureTask<Integer> futureTask = new FutureTask<>(countSum);// 创建FutureTask对象
    
            ExecutorService executorService = Executors.newCachedThreadPool();// 开启线程
            executorService.execute(futureTask);
            try {
                int sum = futureTask.get();
                System.out.println("主线程获得求和结果:" + sum);
            } catch (Exception e) {
                e.printStackTrace();
                futureTask.cancel(true);
            } finally {
                executorService.shutdown();
            }
        }
    

    参考:https://www.jianshu.com/p/16d6f0a22111
    https://www.toutiao.com/i6847669587702612492/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1595402336&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=202007221518550100140481441F0A51AE&group_id=6847669587702612492

    相关文章

      网友评论

          本文标题:每日一结——Future,FutureTask

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