Guava ListenableFuture/springboot CompletableFuture/JavaScript Promise 异步回调

异步调用, 光用@Async也没用, 除非不关系结果 🏙️

真正的爱情是不能用言语表达的,行为才是忠心的最好说明

然而,Java 的 Future 接口并不提供 addListener 这个方法。为了解决这个问题,你可以使用第三方库,如 Google 的 Guava 库,它提供了一个 ListenableFuture 接口,可以让你添加一个回调函数,在任务完成时执行。

以下是一个使用 Guava 的 ListenableFuture 的示例:

首先,将 Guava 库添加到你的项目中。如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

然后,你可以使用 ListenableFutureFutures.addCallback() 方法添加监听器:

import com.google.common.util.concurrent.*;

import java.util.concurrent.Executors;

public class ListenableFutureExample {
    public static void main(String[] args) {
        // 创建一个 ListeningExecutorService
        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));

        // 提交一个异步任务并获得一个 ListenableFuture 对象
        ListenableFuture<Integer> future = executor.submit(() -> {
            System.out.println("Async task is running...");
            Thread.sleep(1000);
            System.out.println("Async task is completed.");
            return 42;
        });

        // 为 ListenableFuture 添加一个回调函数
        Futures.addCallback(future, new FutureCallback<Integer>() {
            @Override
            public void onSuccess(Integer result) {
                System.out.println("Result: " + result);
            }

            @Override
            public void onFailure(Throwable t) {
                t.printStackTrace();
            }
        }, executor);

        // 关闭线程池
        executor.shutdown();
    }
}

在这个示例中,我们使用 MoreExecutors.listeningDecorator() 将普通的 ExecutorService 装饰为 ListeningExecutorService。然后,我们提交一个异步任务并获得一个 ListenableFuture 对象。接下来,我们使用 Futures.addCallback() 方法为 ListenableFuture 添加一个回调函数。这个回调函数包含 onSuccess()onFailure() 方法,分别在任务成功完成和发生异常时执行。最后,我们关闭线程池。

运行上述代码,你将看到以下输出:

Async task is running...
Async task is completed.
Result: 42

在这个示例中,我们没有显式地调用 future.get() 方法来获取计算结果,而是通过在 ListenableFuture 上添加回调函数来实现。这样,我们可以在任务完成时执行相应的操作,而不需要阻塞主线程。

使用 ListenableFuture 可以使你的代码更具可读性,因为你可以在同一个地方定义异步任务和完成时的操作。此外,通过添加回调函数,你可以避免阻塞主线程,从而提高应用程序的响应性能。

总之,FutureListenableFuture 提供了一种处理异步任务的灵活方法。你可以使用它们来获取异步计算结果,或者添加回调函数在任务完成时执行。这有助于提高应用程序的可读性和响应性能。

springboot 实现类似 ListenableFuture 的回调功能

在 Spring Boot 中,可以使用 CompletableFuture 类来实现类似 Guava 库的 ListenableFuture 的回调功能,而不会导致阻塞。CompletableFuture 是 Java 8 中引入的一个功能强大的异步编程工具,它实现了 Future 接口,并提供了一系列非阻塞的回调方法。

下面是一个简单的示例,展示如何在 Spring Boot 项目中使用 CompletableFuture 实现异步回调:

  1. 首先,创建一个异步任务,该任务返回一个 CompletableFuture 对象:
import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {

    @Async
    public CompletableFuture<String> asyncTask() {
        // 模拟耗时操作
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return CompletableFuture.completedFuture("异步任务完成");
    }
}
  1. 在使用异步任务的地方,添加回调方法:
import java.util.concurrent.CompletableFuture;

@Service
public class MyService {

    @Autowired
    private AsyncService asyncService;

    public void executeTask() {
        CompletableFuture<String> future = asyncService.asyncTask();

        // 添加回调方法,处理正常完成的情况
        future.thenAccept(result -> {
            System.out.println("任务完成,结果:" + result);
        });

        // 添加回调方法,处理异常情况
        future.exceptionally(ex -> {
            System.out.println("任务异常:" + ex.getMessage());
            return null;
        });

        // 非阻塞执行
        System.out.println("主线程继续执行");
    }
}

asyncService.asyncTask() 会立即返回一个 CompletableFuture 对象,而不会等待异步任务执行完毕。这是因为 CompletableFuture 本身是一个表示异步计算的占位符,它允许您在稍后的时间点处理异步任务的结果。

当您调用 asyncService.asyncTask() 时,它会在后台启动一个异步任务,并立即返回一个 CompletableFuture 对象。您可以在这个对象上添加回调函数,以便在异步任务完成时执行特定的操作。这些回调函数是非阻塞的,也就是说,它们不会影响主线程的执行。

在上面的例子中,CompletableFuture future = asyncService.asyncTask() 这行代码会立即返回一个 CompletableFuture 对象,然后您可以添加回调方法,如 future.thenAccept() 和 future.exceptionally()。这些回调方法会在异步任务完成或发生异常时被调用,而主线程可以继续执行其他任务。

  1. 最后,确保 Spring Boot 项目已正确配置异步支持:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfiguration {
}

这样,在执行 MyService.executeTask() 方法时,异步任务将在后台运行,并在完成时执行回调方法,主线程可以继续执行其他任务,而不会被阻塞。

感觉有点类似 JavaScript 中 Promise 的用法

Promise

Promise 对象在 JavaScript 中更类似于 Java 中的 CompletableFuture,因为它们都提供了一种处理异步操作的方式,可以对异步操作的完成和失败状态进行处理。

在 JavaScript 中,Promise 对象可以通过构造函数来创建,构造函数需要传递一个执行器函数(executor function),它有两个参数:resolve 和 reject。resolve 函数用于将 Promise 对象的状态设置为成功(fulfilled),并传递一个结果值;reject 函数用于将 Promise 对象的状态设置为失败(rejected),并传递一个错误原因。

例如,以下代码展示了如何创建一个 Promise 对象:

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve('success');
    } else {
      reject('failure');
    }
  }, 1000);
});

这个 Promise 对象会等待 1 秒钟,然后随机决定是成功还是失败,并将相应的状态和值传递给 resolve 和 reject 函数。

要处理 Promise 对象的完成和失败状态,可以使用 then() 方法和 catch() 方法。then() 方法用于注册成功状态的回调函数,catch() 方法用于注册失败状态的回调函数。这些回调函数将在 Promise 对象的状态发生相应变化时被调用,并且可以访问到相应的结果值或错误原因。

例如,以下代码展示了如何使用 then() 方法和 catch() 方法来处理 Promise 对象的状态:

myPromise.then((result) => {
  console.log('Promise resolved with result:', result);
}).catch((error) => {
  console.error('Promise rejected with error:', error);
});

这个代码会注册一个成功状态的回调函数,用于输出成功时的结果值,以及一个失败状态的回调函数,用于输出失败时的错误原因。如果 Promise 对象被解决,则会调用成功回调函数;如果 Promise 对象被拒绝,则会调用失败回调函数。

可以链式调用 then() 方法来处理多个 Promise 对象的状态。例如,以下代码展示了如何使用 Promise 对象的 then() 方法来进行链式调用:

可以链式调用 then() 方法来处理多个 Promise 对象的状态。例如,以下代码展示了如何使用 Promise 对象的 then() 方法来进行链式调用:

promise1().then((result1) => {
  console.log('promise1 resolved with result:', result1);
  return promise2();
}).then((result2) => {
  console.log('promise2 resolved with result:', result2);
  return promise3();
}).then((result3) => {
  console.log('promise3 resolved with result:', result3);
}).catch((error) => {
  console.error('Promise rejected with error:', error);
});

这个代码中,先调用 promise1() 方法,等待它的解决,然后将结果传递给第一个 then() 方法。第一个 then() 方法会调用 promise2() 方法,等待它的解决,并将结果传递给第二个 then() 方法。第二个 then() 方法会调用 promise3() 方法,等待它的解决,并将结果传递给第三个 then() 方法。如果任何一个 Promise 对象被拒绝,都会调用 catch() 方法。

综上所述,Promise 对象提供了一种简单而强大的方式来处理异步操作的状态,可以方便地处理成功和失败的情况,以及链式调用多个 Promise 对象。在 JavaScript 中,Promise 对象是非常常用的异步编程工具,也是一种比较常见的处理异步操作的方式。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值