【问题标题】:Asynchronous non-blocking task with CompletableFutures具有 CompletableFutures 的异步非阻塞任务
【发布时间】:2019-01-24 12:33:12
【问题描述】:

我需要在 Java 8 中创建一个异步、非阻塞任务,我想使用 CompletableFutures 但我不确定它是否满足我的需求。

为了简化案例,假设我们有一个 API 可以为用户检索一些数据,但同时想要启动一个单独的任务来执行一些操作。我不需要也不想等待这个单独的任务完成,我想立即将响应发送给用户。模拟代码示例:

public Response doSomething(params) {
  Object data = retrieveSomeData(params);

  // I don't want to wait for this to finish, I don't care if it succeeds or not
  doSomethingNoWait(data);

  return new Response(data);
}

我在看 CompletableFutures,类似这样的:

CompletableFuture.supplyAsync(this::doSomethingNoWait)  
             .thenApply(this::logSomeMessage); 

我想知道这是否是正确的方法?响应会在 doSomethingNoWait 完成它必须做的事情之前返回给用户吗?

谢谢!

【问题讨论】:

    标签: multithreading java-8 completable-future


    【解决方案1】:

    很好的问题。是的,CompleteableFuture 非常适合您的需求!让我们进一步研究该类的功能。

    CompleteableFutureFuture 类的包装器,允许并行执行。让我们看一个来自this article的例子。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    });
    

    在上面的例子中,程序将异步启动CompletableFuture,并让新线程在后台休眠。如果我们添加.thenApply() 如下所示:

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    }).thenApply(result -> {
       System.out.println(result);
       return "Result of the then apply";
    });
    

    应用程序将像我们之前讨论的那样执行,但是一旦它完成(非异常),运行supplyAsync 的当前线程将执行打印语句。

    注意,如果同步转换在执行完成后添加到未来,调用线程将执行转换。如下所示:

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Result of the asynchronous computation";
    });
    // Long calculations that allows the future above to finish
    future.thenApply(result -> {
       System.out.println(result);
       return "Result of the then apply";
    });
    

    thenApply 将在运行future.thenApply(...) 的线程上运行,而不是在后台运行supplyAsync 的线程。

    【讨论】:

    • 听起来很完美,我不知何故错过了 thenApplyAsync 方法。谢谢!
    • System.out.println(result); 之后缺少返回语句
    • "调用线程将执行打印语句"。那会是哪个?你是说你知道哪个线程会执行thenApply
    • 我试图用最近的编辑来澄清我的答案
    • 将异步任务委托给新线程(Executor Instances)的事实,它仍然不是完全非阻塞/事件驱动的方法,对吧?执行程序线程被任何阻塞调用阻塞,后续任务被队列到 threadPool 对吗?所以它更多的是并行执行而不是非阻塞执行。希望我的理解是正确的! @杂质
    【解决方案2】:

    "thenApply(this::logSomeMessage)" 只有在 "supplyAsync(this::doSomethingNoWait)" 阶段正常完成时才会执行。

    你可以这样做:

    CompletableFuture.supplyAsync(this::doSomethingNoWait)  
    logSomeMessage()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-06
      • 1970-01-01
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 2017-07-07
      • 2011-05-07
      相关资源
      最近更新 更多