gpt4 book ai didi

java - CompletableFuture 是否保证在新线程中运行?

转载 作者:行者123 更新时间:2023-12-04 11:50:10 25 4
gpt4 key购买 nike

给定一些任意的上下文(例如 Junit 单元测试,而不是特别是不一定是“主”线程)。
像这样的代码必须引入至少 2 个线程吗?

public static void main (String[] args)
{
CompletableFuture<Void> s = new CompletableFuture<>();
CompletableFuture<Void> f = new CompletableFuture<>();

CompletableFuture<Void> someContext = CompletableFuture.supplyAsync(() ->
{
try{
System.out.println(Thread.currentThread().getId());
CompletableFuture<String> update =
CompletableFuture.supplyAsync(
() -> {
String ans = null;
try {
System.out.println(Thread.currentThread().getId());
ans = "Hello";
} catch (Exception e) {
ans = e.toString();
} finally {
s.complete(null);
return ans;
}
});
s.get();
System.out.println(s.isDone());
} catch (Exception e) {
System.out.println("Some error");
return null;
}
return null;
});

System.out.println(f.isDone());
}
当我们到达 s.get()someContext JVM 能否检测到它正在等待 -> 上下文切换到 update完成它,然后切换回 someContext ?
ideone 中运行时它始终在两个不同的线程中运行它们,但这只是单个观察。
我想了解语言/运行时提供的保证。

最佳答案

不,此保证不存在。
你在做什么是不安全的。
如果您查看 CompletableFuture.supplyAsync(Supplier) 的文档:

Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() with the value obtained by calling the given Supplier.


你可以看到它使用了 ForkJoinPoolForkJoinPool.commonPool() 获得.
来自 ForkJoinPool 的文档:

all threads in the pool attempt to find and execute tasks submitted to the pool and/or created by other active tasks (eventually blocking waiting for work if none exist). This enables efficient processing when most tasks spawn other subtasks (as do most ForkJoinTasks), as well as when many small tasks are submitted to the pool from external clients. Especially when setting asyncMode to true in constructors, ForkJoinPools may also be appropriate for use with event-style tasks that are never joined. All worker threads are initialized with Thread.isDaemon() set true.A static commonPool() is available and appropriate for most applications. The common pool is used by any ForkJoinTask that is not explicitly submitted to a specified pool. Using the common pool normally reduces resource usage (its threads are slowly reclaimed during periods of non-use, and reinstated upon subsequent use).For applications that require separate or custom pools, a ForkJoinPool may be constructed with a given target parallelism level; by default, equal to the number of available processors


这意味着提交的任务可以在任意数量的线程(默认为处理器数量)中执行,并且这些线程会被重用。如果所有这些线程都忙,则执行可能会等待先前的执行完成。
由于公共(public)池也可能被应用程序的其他部分使用,提交的任务应该很快运行,不应阻塞,以便其他任务可以快速执行。
虽然 OpenJDK has a special handling for ForkJoinPool in CompletableFuture#get 确保在此期间可以执行其他任务,其他 JDK 可能不提供此功能。
替代方案:异步处理
而不是阻塞使用 .get() ,你可能想使用像 CompletableFuture#thenAcceptAsync(Consumer) 这样的方法.这将运行 Consumer future 结束后。
此外,您可以使用 CompletionStage#exceptionally以异步方式处理异常。
public static void main (String[] args) throws java.lang.Exception
{
CompletableFuture<Void> s = new CompletableFuture();
CompletableFuture<Void> f = new CompletableFuture();

CompletableFuture<Void> someContext = CompletableFuture.supplyAsync(() ->
{

System.out.println(Thread.currentThread().getId());
CompletableFuture<String> update =
CompletableFuture.supplyAsync(
() -> {
String ans = null;
try {
System.out.println(Thread.currentThread().getId());
ans = "Hello";
} catch (Exception e) {
ans = e.toString();
} finally {
s.complete(null);
return ans;
}
});
s thenSupplyAsync(result->{
System.out.println(s.isDone());
}).exceptionally(e->{
System.out.println("Some error");
return null;
});

return null;
});

System.out.println(f.isDone());
}

关于java - CompletableFuture 是否保证在新线程中运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68123106/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com