Future模式

89 阅读3分钟

Future模式是多线程开发中常用常见的一种设计模式,它的核心思想是异步调用。在调用一个函数方法时候,如果函数执行很慢,我们就要进行等待,但这时我们可能不着急要结果,因此我们可以让被调者立即返回,让它在后台慢慢处理这个请求,对于调用者来说可以先处理一些其他事物,在真正需要数据的场合再去尝试获得需要的数据。对于Future模式来说,虽然它无法立即给出你需要的数据,但是它们返回一个契约给你,将来你可以凭借这个契约去重新获取你需要的信息。

Java中的Future对象主要用于异步编程,‌允许程序在等待某个操作完成时继续执行其他任务。‌

  • Future的基本概念:‌Future对象代表了一个异步计算的结果。‌当这个计算完成时,‌结果会被保存在Future对象中。‌通过Future,‌我们可以暂时处理其他任务,‌而无需一直等待结果,‌等异步任务执行完毕再返回其结果1。‌

  • Future的使用场景:‌

    • 当执行一个长时间运行的任务时,‌使用Future可以让我们暂时去处理其他的任务,‌等长任务执行完毕再返回其结果。‌这适用于计算密集场景、‌处理大数据量、‌远程方法调用等场景2。‌
    • Future模式可以让程序更加灵活和高效,‌优化程序的性能,‌提高用户体验,‌因为用户不需要等待一个操作完成才能进行下一个操作3。‌
  • Future的主要方法:‌

    • get() 方法用于获取异步任务的结果。‌如果任务还没有结束,‌get() 方法会阻塞线程直到任务完成。‌此外,‌还有一个带超时的 get(long timeout, TimeUnit unit) 方法,‌允许在等待一定时间后如果任务仍未完成则抛出 TimeoutException1。‌
    • isDone() 方法用于检查异步任务是否已经完成3。‌
  • Future的实现:‌

    • 通过 ExecutorService 的 submit() 方法提交一个 Callable 任务来获取一个 Future 对象。‌Callable 接口类似于 Runnable,‌但它允许返回一个结果12。‌
    • 使用 Future 时,‌可以通过实现 Callable 接口并重写 call() 方法来定义异步任务。‌call() 方法可以抛出异常并返回结果12。‌
  • 使用Future的注意事项:‌

    • 当使用 get() 方法获取结果时,‌如果任务未完成,‌调用线程会被阻塞。‌因此,‌需要谨慎处理这种情况,‌避免死锁或资源浪费1。‌
    • 在多线程环境中使用 Future 时,‌应注意线程安全和资源管理,‌确保在任务完成后正确关闭资源3。‌

通过上述介绍,‌我们可以看到Java中的Future机制为并发编程提供了灵活的解决方案,‌使得程序能够在等待异步任务完成的同时继续执行其他任务,‌提高了程序的效率和响应性。‌

关键点

  • Future用于表示异步执行的结果,能够对Runnable和Callable任务的执行结果进行管理。
  • 通过Future对象的get()方法可以获取异步执行的结果,该方法会阻塞直到任务完成。
  • Future提供了cancel方法用于取消尚未执行或正在执行的任务。
  • isDone方法可以用来检查任务是否已经完成。
  • CompletableFuture是对Future模式的增强版本,提供了回调机制以优化异步执行。
  • CompletableFuture支持两个接口,分别是Future和CompletionStage,增强了异步编程的灵活性。
  • Runnable和Callable分别用于没有返回结果和有返回结果的任务,使得Future能够更加有效地管理不同类型的任务。

代码示例

public class FutureTest {

    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newFixedThreadPool(4);
        Future<BigDecimal> future = es.submit(new Task("601857"));
        System.out.println(future.get());
        es.shutdown();
    }
}

class Task implements Callable<BigDecimal> {
    public Task(String code) {
    }

    @Override
    public BigDecimal call() throws Exception {
        Thread.sleep(1000);
        double d = 5 + Math.random() * 20;
        return new BigDecimal(d).setScale(2, RoundingMode.DOWN);
    }
}