简体   繁体   English

然后应用于CompletableFuture

[英]thenApply in CompletableFuture

In the following code 在下面的代码中

public CompletableFuture<String> getMyFuture(String input)
    {   
        CompletableFuture<String> future = new CompletableFuture<String>().thenApply((result) -> result+ "::");
        ExecutorService service = Executors.newFixedThreadPool(6);
        service.submit(() -> {      
            try {
                future.complete(getResult(input));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return future;
    }

    public String getResult(String input) throws InterruptedException
    {
        Thread.sleep(3000);
        return "hello "+ input +" :" + LocalTime.now();
    }

I am expecting the output to contain trailing "::" but program doesn't is "hello first :16:49:30.231 " Is my implementation of apply correct ? 我期望输出包含尾部的“ ::”,但程序不是“ hello first:16:49:30.231”我的apply实现正确吗?

You're invoking complete() method of the CompletionStage that you got at the first line (where you call "thenApply" method). 您正在调用第一行获得的CompletionStage complete()方法(在此处称为“ thenApply”方法)。

If your intention is to complete the CompletableFuture with some string value ( future.complete(getResult(input)) ) and then apply some function, you'd better place thenApply() at the end (where you return the future). 如果您打算用某个字符串值( future.complete(getResult(input)) )完成CompletableFuture并应用一些函数,则最好将thenApply()放在最后(返回未来)。

public CompletableFuture<String> getMyFuture(String input)
    {
        CompletableFuture<String> future = new CompletableFuture<String>();
        ExecutorService service = Executors.newFixedThreadPool(6);
        service.submit(() -> {
            try {
                future.complete(getResult(input));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return future.thenApply(result -> result+ "::");
    }

I don't know how to explain it in a more understandable way. 我不知道如何以更容易理解的方式解释它。 But in short: you're calling complete() method on the wrong object reference inside your Runnable . 但简而言之: 您正在对 Runnable 错误的对象引用调用complete()方法

You are creating two CompletableFuture instances. 您正在创建两个 CompletableFuture实例。 The first, created via new CompletableFuture<String>() will never get completed, you don't even keep a reference to it that would make completing it possible. 第一个是通过new CompletableFuture<String>()创建的,它将永远不会完成,您甚至不会保留对其进行引用的引用,从而无法完成。

The second, created by calling .thenApply((result) -> result+ "::") on the first one, could get completed by evaluating the specified function once the first one completed, using the first's result as an argument to the function. 通过在第一个函数上调用.thenApply((result) -> result+ "::")创建的第二个函数,可以在第一个函数完成后通过评估指定的函数来完成,并使用第一个函数的结果作为函数的参数。 However, since the first never completes, the function becomes irrelevant. 但是,由于第一个永远不会完成,因此该功能变得无关紧要。

But CompletableFuture instances can get completed by anyone, not just a function passed to a chaining method. 但是CompletableFuture实例可以由任何人完成,而不仅仅是传递给链接方法的函数。 The possibility to get completed is even prominently displayed in its class name. 完成的可能性甚至在班级名称中突出显示。 In case of multiple completion attempts, one would turn out to be the first one, winning the race and all subsequent completion attempts will be ignored. 如果进行了多次完成尝试,那么结果将是第一个赢得比赛,并且所有后续完成尝试都将被忽略。 In your code, you have only one completion attempt, which will successfully complete it with the value returned by getResult , without any adaptations. 在您的代码中,您只有一次完成尝试,它将使用getResult返回的值成功完成它,而无需进行任何修改。

You could change your code to keep a reference to the first CompletableFuture instance to complete it manually, so that the second gets completed using the function passed to thenApply , but on the other hand, there is no need for manual completion here: 您可以更改代码以保留对第一个CompletableFuture实例的引用,以手动complete它,以便使用传递给thenApply的函数来完成第二个thenApply ,但是另一方面,这里不需要手动完成:

public CompletableFuture<String> getMyFuture(String input) {   
    ExecutorService service = Executors.newFixedThreadPool(6);
    return CompletableFuture.supplyAsync(() -> getResult(input), service)
                            .thenApply(result -> result + "::");
}
public String getResult(String input) {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
    return "hello "+ input +" :" + LocalTime.now();
}    

When specifying the executor to supplyAsync , the function will be evaluated using that executor. 将执行程序指定为supplyAsync ,将使用该执行程序对函数进行评估。 More is not needed. 不需要更多。

Needless to say, that's just for example. 不用说,这只是举例。 You should never create a temporary thread pool executor, as the whole point of a thread pool executor is to allow reusing the threads (and you're using only one of these six threads at all) and it should get shut down after use. 您永远不应创建一个临时线程池执行程序,因为线程池执行程序的全部目的是允许重用线程(并且您仅使用这六个线程之一),并且在使用后应将其关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM