写点什么

CompletableFuture 实现异步转同步

作者:FunTester
  • 2023-02-07
    北京
  • 本文字数:1544 字

    阅读完需:约 5 分钟

在很早之前的文章服务端性能优化之异步查询转同步介绍了一种常用到,服务端开发常用到的多个异步查询转同步的方法,本质上就是利用了java.util.concurrent.CountDownLatch的功能特性,将几个异步查询任务都设置一个java.util.concurrent.CountDownLatch实例,然后等待所有异步任务完成再组装响应,同步返回给客户端。

最近通过对java.util.concurrent包的继续学习,又掌握了java.util.concurrent.CompletableFuture这个类的基本使用,使用场景一个请求过来之后,需要等待另外一个异步任务完成之后,获取响应结果。特别适合 WebSocket 场景,比如 A 向 B 发送了一条消息,需要等待 B 把消息发过来这种场景。

下面我用一个简单的例子来演示一下java.util.concurrent.CompletableFuture如何使用,先分享一个 Java 版本:

import com.funtester.frame.SourceCode;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;
public class PerFunTest extends SourceCode {
    private static final Logger log = LogManager.getLogger(PerFunTest.class);
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {        log.info("测试开始");        CompletableFuture<String> future = new CompletableFuture<String>();        new Thread(() -> {            sleep(1.0);            future.complete("FunTester");            log.info("赋值结束");        }).start();        String get = future.get(5, TimeUnit.SECONDS);        if (get != null) log.info("取值: {}", get);
    }
}

复制代码

控制台输出:

20:38:47.648 main 测试开始20:38:48.654 main 取值: FunTester20:38:48.654 Thread-1 赋值结束

复制代码

这里我们可以看到 47 秒测试开始,然后是 48 秒赋值结束和取值几乎同时完成。如果我们在 thread 中的 sleep 时间超过了 get 超时时间,就会报错。这里可以避免某个异步消息来得太晚导致接口响应时间过长。

下面我展示一下 Groovy 的实践,可以对比体验一下:

import com.funtester.frame.SourceCodeimport groovy.util.logging.Log4j2
import java.util.concurrent.CompletableFutureimport java.util.concurrent.TimeUnit
@Log4j2class Ts extends SourceCode {
    static void main(String[] args) {        log.info("测试开始")        def future = new CompletableFuture<String>()        fun {            sleep(1.0)            future.complete("FunTester")            log.info("赋值结束")        }        def get = future.get(5, TimeUnit.SECONDS)        if (get != null) log.info("取值: $get")    }}

复制代码

对于异步转同步的场景实践,就分享到这里。对于对 Java 多线程编程有兴趣的小伙伴,可以多看java.util.concurrent包里面的实现类的代码和逻辑。本人实践,获益匪浅。

FunTester 原创专题推荐~

-- By FunTester

发布于: 刚刚阅读数: 3
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
CompletableFuture实现异步转同步_FunTester_InfoQ写作社区