在以下代码中
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();
}
我希望输出包含尾随“::”但程序不是“你好先:16:49:30.231 “我的申请是否正确?
答案 0 :(得分:2)
您正在调用第一行complete()
的{{1}}方法(您调用&#34;然后应用&#34;方法)。
如果您打算使用某个字符串值(CompletionStage
)完成CompletableFuture
然后应用某些功能,那么最好将future.complete(getResult(input))
放在最后(您在哪里)回归未来)。
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+ "::");
}
内的错误对象引用上调用了complete()
方法。
答案 1 :(得分:1)
您正在创建两个 CompletableFuture
个实例。第一个是通过new CompletableFuture<String>()
创建的,永远不会完成,你甚至不会保留对它的引用来完成它。
第二个,通过在第一个上调用.thenApply((result) -> result+ "::")
创建的,可以通过在第一个完成后使用第一个结果作为函数的参数来评估指定函数来完成。但是,由于第一个从未完成,因此该功能变得无关紧要。
但CompletableFuture
实例可以由任何人完成,而不仅仅是传递给链接方法的函数。完成的可能性甚至在其类名中突出显示。在多次完成尝试的情况下,一个将成为第一个,赢得比赛并且所有后续完成尝试将被忽略。在您的代码中,您只有一次完成尝试,它将使用getResult
返回的值成功完成它,而不进行任何调整。
您可以更改代码,以便手动将第一个CompletableFuture
实例引用到complete
,以便第二个使用传递给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();
}
将执行程序指定为supplyAsync
时,将使用该执行程序评估该函数。不需要更多。
毋庸置疑,仅举例来说。你永远不应该创建一个临时线程池执行器,因为线程池执行器的重点是允许重用线程(并且你只使用这六个线程中的一个),它应该在使用后关闭。 / p>