Future 接口详细解读

一、Future 的应用场景
  • 在并发编程中,我们经常需要用非阻塞的模型,Java 默认多线程的三种实现中,继承 Thread 类和实现 Runnable 接口是异步并且主调函数是无法获取到返回值的。通过实现 Callback 接口,并用 Future 可以来接收多线程的执行结果

  • Future 接收一个可能还没有完成的异步任务的结果,针对这个结果可以添加 Callable 以便任务执行成功或失败后作出相应的操作

  • 采用 Future 修改的异步方法,在每次被异步调用以后会马上返回(无论一步方法体是否执行完成),Future 就会监听异步任务执行状态(成功、失败),等到执行完成以后,就能通过 Future.get() 方法获取到异步返回的结果

  • 也就是说,如果批量调用采用 Future 修饰的异步方法,程序不会阻塞等待,然后再遍历 Future 列表,即可获取到所有的异步结果(Future 的内部机制是等所有的异步任务完成了才进行遍历), 这种请求耗时只会略大于耗时最长的一个 Future 修饰的方法

二、Future 的类图结构

mark

  • RunnableFuture

    • RunnableFuture 接口同时继承了 Future 接口和 Runnable 接口,在成功执行完成 run() 以后,可以通过 Future 访问执行结果

    • RunnableFuture 接口的实现类是 FutureTaskFutureTask 是一个可取消的异步计算,FutureTask 类提供了 Future 的基本实现,(取消、判断是否取消、判断是否完成、获取异步结果(阻塞)、有限时间获取异步结果(阻塞))

    • FutureTask 能用来包装一个 CallableRunnable 对象,因为它实现了 Runnable 接口,而且它能被传递到 Executor 进行执行,为了提供单例类,这个类再创建自定义的工作类时提供了 protected 构造函数

  • SchedualFuture

    • SchedualFuture 表示一个延时的行为可以被取消,通常一个安排好的 Future 是定时任务 SchedualedExecutorService 的结果
  • CompleteFuture

    • 一个 Future 类是显示的完成,而且能被用作一个完成等级,通过它完成触发支持的依赖函数和行为。当两个或多个线程要执行完成或取消操作时,只有一个能够成功
  • ForkJoinTask

    • 基于任务的抽象类,可以通过 ForkJoinPool 来执行。一个 ForkJoinTask 是类似于线程实体,但是相对于线程实体是轻量级的。大量的任务和子任务会被 ForkJoinPool 池中的真实线程挂起来,以某些使用限制为代价
三、Future 的接口方法

2

  • cancel(boolean mayInterruptIfRunning) 用来停止一个任务,如果任务可以被停止(通过 mayInterruptIfRunning 来进行判断),则可以返回 true,如果任务已经完成、已经停止或者无法停止,则会返回 false

  • isCancelled 用来判断当前方法是否取消

  • isDone 用来判断当前方法是否完成

  • get 当异步任务结束后返回一个结果,如果调用 get() 时任务还没有结束,那么调用线程将会阻塞,直到有返回结果为止

  • get(long time, TimeUnit unit) 最多等待 timeout 的时间就会返回结果,不管异步任务是否执行完成

四、Future 的应用示例
  • 测试代码

    public class C98_Future {
    
        public Future rice() {
            long start = System.currentTimeMillis();
            try {
                System.out.println("线程:" + Thread.currentThread().getName() + "------> 开始做饭");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "------> 完成做饭,耗时:" + (System.currentTimeMillis() - start) + " ms");
            return null;
        }
    
        public Future<String> soup() {
            long start = System.currentTimeMillis();
            try {
                System.out.println("线程:" + Thread.currentThread().getName() + "------> 开始煲汤");
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "------> 完成煲汤,耗时:" + (System.currentTimeMillis() - start) + " ms");
            return null;
        }
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            long start = System.currentTimeMillis();
            // JOIN 方法阻塞等待
    //        Thread rice = new CookRice();
    //        rice.start();
    //        rice.join();
    //
    //        CookSoup soup = new CookSoup();
    //        soup.start();
    //        soup.join();
    
            // Future 方式非阻塞执行,阻塞等待结果
            Callable callable1 = ()-> {{
                    new C98_Future().rice();
                    return "Finish1";
                }
            };
    
            FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
            new Thread(futureTask1).start();
    
            Callable callable2 = ()-> {{
                new C98_Future().soup();
                return "Finish2";
            }
            };
    
            FutureTask<String> futureTask2 = new FutureTask<String>(callable2);
            new Thread(futureTask2).start();
            System.out.println(futureTask1.get());
            System.out.println(futureTask2.get());
    
            System.out.println("全部准备完毕时间:" + (System.currentTimeMillis() - start) + " ms");
        }
    }
    
    class CookRice extends Thread {
    
        @Override
        public void run() {
            new C98_Future().rice();
        }
    }
    
    class CookSoup extends Thread {
        @Override
        public void run() {
            new C98_Future().soup();
        }
    }
    
  • JOIN 方法阻塞等待结果

    线程:Thread-0------> 开始做饭
    线程:Thread-0------> 完成做饭,耗时:2006 ms
    线程:Thread-1------> 开始煲汤
    线程:Thread-1------> 完成煲汤,耗时:5005 ms
    全部准备完毕时间:7012 ms
    
  • Future 方式非阻塞执行,阻塞等待结果

    线程:Thread-0------> 开始做饭
    线程:Thread-1------> 开始煲汤
    线程:Thread-0------> 完成做饭,耗时:2005 ms
    Finish1
    线程:Thread-1------> 完成煲汤,耗时:5005 ms
    Finish2
    全部准备完毕时间:5055 ms
    
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值