Java的Future机制详解

一、为什么出现Future机制

常见的两种创建线程的方式。一种是直接继承Thread,另外一种就是实现Runnable接口。这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。Future模式的核心思想是能够让主线程将原来需要同步等待的这段时间用来做其他的事情。(因为可以异步获得执行结果,所以不用一直同步等待去获得执行结果)

二、回顾Java创建线程的几种方式

回顾Java创建线程的几种方式

三、详解异步调用

场景一:(future.get 堵塞模式)

先假设一个场景:假如你想做饭,但是没有厨具,也没有食材。而网上购买厨具比较方便,食材去超市买更放心。于是你在网上下单买厨具,但是等快递的时候不能啥也不干,可以利用这段时间去超时买菜。

这种场景在实际业务中很多:你想调用X接口,但是这个接口下游依赖其他两个接口A,B,且A、B没有依赖关系。假设A接口的执行和返回需要300ms,B接口的执行和返还需要150ms。

如果串行执行,则总共需要:300 + 150 = 450ms。而如果并行执行,则只需要 max(300,150)= 300ms。

public class FuturePractice {
    //  用线程A,B的结果组成输出
    static void getResult(ThreadA threadA, ThreadB threadB) {
    }

    // 线程A
    static class ThreadA {
    }

    // 线程B
    static class ThreadB {
    }

    // 假设main函数就是X接口
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();
        // 查询A接口
        Callable<ThreadA> threadA = new Callable<ThreadA>() {
            @Override
            public ThreadA call() throws Exception {
                System.out.println("异步调用线程A");
                System.out.println("线程A查询中");
                Thread.sleep(300);
                System.out.println("线程A返回结果");
                return new ThreadA();
            }
        };
        FutureTask<ThreadA> futureA = new FutureTask<ThreadA>(threadA);
        new Thread(futureA).start();

        // 查询B接口
        Callable<ThreadB> threadB = new Callable<ThreadB>() {
            @Override
            public ThreadB call() throws Exception {
                System.out.println("异步调用线程B");
                System.out.println("线程B查询中");
                Thread.sleep(150);
                System.out.println("线程B返回结果");
                return new ThreadB();
            }
        };

        FutureTask<ThreadB> futureB = new FutureTask<ThreadB>(threadB);
        new Thread(futureB).start();
        // 使用A、B接口的值组成返回值
        if (!futureA.isDone() && !futureB.isDone()) {
            System.out.println("A、B接口并未查询结束");
        }
        ThreadA threadAResult = futureA.get();//同步堵塞
        ThreadB threadBResult = futureB.get();//同步堵塞
        System.out.println("A、B接口查询完毕,返回X接口结果");
        getResult(threadAResult, threadBResult);

        System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");
        
    }
}

输出结果:(观察输出结果即可明白整个过程)

异步调用线程A
线程A查询中 
A、B接口并未查询结束
异步调用线程B
线程B查询中
线程B返回结果
线程A返回结果
A、B接口查询完毕,返回X接口结果
总共用时305ms

场景二:(future 回调模式 效率最高

举个通俗的例子:打电话,有一天小王遇到一个很难的问题,问题是“1 + 1 = ?”,就打电话问小李,小李一下子也不知道,就跟小王说,等我办完手上的事情,就去想想答案,小王也不会傻傻的拿着电话去等小李的答案吧,于是小王就对小李说,我还要去逛街,你知道了答案就打我电话告诉我,于是挂了电话,自己办自己的事情,过了一个小时,小李打了小王的电话,告诉他答案是2 。

跟第一个场景其实很像,你想调用X接口,但是这个接口下游依赖其他接口A(简化场景1)。且你还有其他事要做,不能干等A的结果。于是采用回调的方式,告诉A,B拿到结果后通告我一声。

回调函数例子见:一个经典例子让你彻彻底底理解java回调机制

Guava对fature的拓展:Future 异步回调 大起底之 Java Future 与 Guava Future

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Future是用于异步计算的接口。它代表了一个可获取结果的异步操作,并提供了方法来检查操作是否完成、等待操作完成并获取结果。使用Future,我们可以在一个线程中启动一个耗时的任务,在另一个线程中继续执行其他操作,待任务完成后再获取其结果。 Future接口定义了以下主要方法: - `boolean isDone()`: 判断任务是否已完成。 - `boolean cancel(boolean mayInterruptIfRunning)`: 尝试取消任务的执行。 - `boolean isCancelled()`: 判断任务是否已被取消。 - `V get() throws InterruptedException, ExecutionException`: 等待任务完成并获取结果。 - `V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException`: 在指定时间内等待任务完成并获取结果。 Future接口的实现类是FutureTask,它可以通过Callable或Runnable任务来创建。我们可以使用ExecutorService.submit()方法提交任务并返回一个Future对象,通过该对象可以获取任务的执行结果。 以下是一个使用Future的简单示例: ```java import java.util.concurrent.*; public class FutureExample { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(1); Future<Integer> future = executor.submit(() -> { Thread.sleep(2000); return 42; }); // 执行其他操作 try { Integer result = future.get(); // 阻塞等待任务执行完成,并获取结果 System.out.println("任务结果:" + result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } executor.shutdown(); } } ``` 在上面的例子中,我们使用ExecutorService提交一个任务,该任务会在2秒后返回结果42。在主线程中执行其他操作后,通过future.get()方法阻塞等待任务的完成,并获取其结果。 需要注意的是,如果任务已经完成,调用get()方法会立即返回结果,否则会阻塞等待任务完成。如果我们希望在指定时间内获取结果,可以使用带有超时参数的get()方法。 这就是关于JavaFuture的简单介绍。希望能对你有所帮助!如果你还有其他问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值