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 对象是非常常用的异步编程工具,也是一种比较常见的处理异步操作的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值