文章目录

  • 一、Future 的应用场景
  • 二、Future 的类图结构
  • 三、Future 的接口方法
  • 四、Future 的应用示例


一、Future 的应用场景
  • 在并发编程中,我们经常需要用非阻塞的模型,Java 默认多线程的三种实现中,继承 Thread 类和实现 Runnable 接口是异步并且主调函数是无法获取到返回值的。通过实现 Callback 接口,并用 Future 可以来接收多线程的执行结果
  • Future 接收一个可能还没有完成的异步任务的结果,针对这个结果可以添加 Callable 以便任务执行成功或失败后作出相应的操作
  • 采用 Future 修改的异步方法,在每次被异步调用以后会马上返回(无论一步方法体是否执行完成),Future 就会监听异步任务执行状态(成功、失败),等到执行完成以后,就能通过 Future.get() 方法获取到异步返回的结果
  • 也就是说,如果批量调用采用 Future 修饰的异步方法,程序不会阻塞等待,然后再遍历 Future 列表,即可获取到所有的异步结果(Future 的内部机制是等所有的异步任务完成了才进行遍历), 这种请求耗时只会略大于耗时最长的一个 Future 修饰的方法
二、Future 的类图结构

java future get多次结果一样吗 future.get作用_并发编程

  • 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 的接口方法

java future get多次结果一样吗 future.get作用_java_02

  • 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