在以下代码中
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();
}
我期望输出包含尾随"::“但是程序不是"hello first :16:49:30.231”,我的应用程序实现正确吗?
发布于 2017-09-22 11:40:50
您正在调用在第一行获得的CompletionStage
的CompletionStage
方法(在这里您调用"thenApply“方法)。
如果您的目的是使用一些字符串值( 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()
中调用错误的对象引用的Runnable
方法。
发布于 2017-09-22 15:34:36
您正在创建两个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
时,将使用该执行器计算函数。不需要更多。
不用说,这只是举个例子。您不应该创建临时线程池执行器,因为线程池执行器的全部目的是允许重用线程(而且您只使用这六个线程中的一个),并且在使用之后应该关闭它。
https://stackoverflow.com/questions/46363626
复制相似问题