gpt4 book ai didi

java - 如何避免使用递归调用使 executorservice 拥塞/停滞/死锁

转载 作者:行者123 更新时间:2023-11-29 07:23:40 33 4
gpt4 key购买 nike

ExecutorService 中的所有线程都忙于等待执行程序服务队列中卡住的任务。

示例代码:

ExecutorService es=Executors.newFixedThreadPool(8);
Set<Future<Set<String>>> outerSet=new HashSet<>();
for(int i=0;i<8;i++){
outerSet.add(es.submit(new Callable<Set<String>>() {

@Override
public Set<String> call() throws Exception {
Thread.sleep(10000); //to simulate work
Set<Future<String>> innerSet=new HashSet<>();
for(int j=0;j<8;j++) {
int k=j;
innerSet.add(es.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "number "+k+" in inner loop";
}

}));
}
Set<String> out=new HashSet<>();
while(!innerSet.isEmpty()) { //we are stuck at this loop because all the
for(Future<String> f:innerSet) { //callable in innerSet are stuckin the queue
if(f.isDone()) { //of es and can't start since all the threads
out.add(f.get()); //in es are busy waiting for them to finish
}
}
}
return out;
}
}));
}

除了为每一层创建更多线程池或使用大小不固定的线程池之外,还有什么方法可以避免这种情况?

一个实际的例子是,如果一些可调用对象被提交给 ForkJoinPool.commonPool(),然后这些任务使用的对象也在它们的方法之一中提交给 commonPool。

最佳答案

您应该使用 ForkJoinPool。它就是为这种情况而制作的。

虽然您的解决方案在等待其子任务完成时永久阻塞线程,但窃取 ForkJoinPool 的工作可以在 join() 中执行工作。这使得它对于这些类型的情况非常有效,在这些情况下,您可能正在运行数量可变的小型(并且通常是递归的)任务。对于常规线程池,您需要扩大它的大小,以确保您不会用完线程。

使用 CompletableFuture,您需要自己处理更多的实际计划/安排,如果您决定更改内容,调整起来会更加复杂。使用 FJP,您唯一需要调整的是池中的线程数量,使用 CF,您需要考虑 thenthenAsync 也是如此。

关于java - 如何避免使用递归调用使 executorservice 拥塞/停滞/死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58812542/

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