当前位置: 首页 > 知识库问答 >
问题:

如何避免使用递归调用的executorservice拥塞/停顿/死锁

苏富
2023-03-14

ExecutorService中的所有线程都在忙着等待滞留在executor服务队列中的任务的任务。

示例代码:

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(),然后这些任务在其方法中使用也提交给CommonPoole的对象。

共有1个答案

呼延原
2023-03-14

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

当线程等待其子任务完成时,您的解决方案会永久阻止它,而窃取forkjoinpool的工作可以在join()中执行工作。这使得它对于正在运行的小(通常是递归的)任务的数量可变的情况非常有效。对于常规线程池,您需要将其放大,以确保线程不会耗尽。

使用completablefuture,您需要自己处理更多的实际计划/日程安排,如果您决定更改内容,则调整将更加复杂。使用fjp时,您唯一需要优化的是池中的线程数量,而使用cf时,您还需要考虑thenthenasync

 类似资料:
  • 问题内容: 我有这样的代码: 实例化B可以按预期工作,但是实例化C无限递归并导致堆栈溢出。我该如何解决? 问题答案: 实例化C调用时,仍然是C,因此super()调用将其带回B。 调用super()时,请直接使用类名。因此,在B中,请致电,而不是(最好在C中使用)。在Python 3中,您可以仅使用不带参数的super()来实现同一目的

  • 问题内容: 我想定义一个包含和方法的类,可以按如下方式调用该类: 为了不使用隔行扫描类,我的想法是覆盖和方法并检查给定名称是否将return重定向到。但是我遇到了无限递归的问题。示例代码如下: 正如在代码中尝试创建新属性一样,它调用,再次调用,依此类推。我怎么需要更改此代码,即,在这种情况下,一个新的属性的创建,持有的价值? 还是有更好的方法来处理“映射”到的呼叫? 总是有关于为什么的问题:我需要

  • 问题内容: 我正在编写一个函数,该函数最多可以调用5000次。当然,我得到了。有什么办法可以以一种非常简单的方式重写此代码?: 顺便说一下,我们可以调用这些函数的深度有什么限制? 问题答案: 使用显式的对象堆栈和循环,而不是调用堆栈和递归:

  • 主要内容:示例资源分配图是系统状态的图形表示。 顾名思义,资源分配图是关于持有一些资源或等待某些资源的所有进程的完整信息。 它还包含有关所有资源的所有实例的信息,无论这些资源是否可用或正在被进程使用。 在资源分配图中,进程由圆形表示,而资源由矩形表示。 我们来详细看看顶点和边的类型。 顶点主要有两种类型,资源和过程。 它们中的每一个将以不同的形状表示。 Circle代表进程,而矩形代表资源。 一个资源可以有多个

  • 在避免死锁的情况下,如果系统的结果状态不会导致系统中的死锁,那么将会授予对任何资源的请求。系统的状态将持续检查安全和不安全的状态。 为了避免死锁,进程必须告诉OS,进程可以请求完成其执行的最大资源数量。 最简单和最有用的方法指出,流程应声明它可能需要的每种类型的最大资源数量。 死锁避免算法检查资源分配,以便永远不会有循环等待条件。 安全和不安全的状态 系统的资源分配状态可以由可用资源和已分配资源的