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

无响应的执行元系统:ThreadPoolExecutor调度器只创建核心线程池,显然忽略了最大线程池大小

娄利
2023-03-14
    null
{"akka" : { "actor" : { "default-dispatcher" : {
    "type" : "Dispatcher",
    "executor" : "default-executor",
    "throughput" : "1",
    "default-executor" : { "fallback" : "thread-pool-executor" }
    "thread-pool-executor" : {
        "keep-alive-time" : "60s",
        "core-pool-size-min" : coreActorCount,
        "core-pool-size-max" : coreActorCount,
        "max-pool-size-min" : maxActorCount,
        "max-pool-size-max" : maxActorCount,
        "task-queue-size" : "-1",
        "task-queue-type" : "linked",
        "allow-core-timeout" : "on"
}}}}}

其他地方配置了工人数,当前workercount=8CoreActorCountWorkerCount+3MaxActorCountWorkerCount*3+5。我在一台拥有两个核心和8GB内存的Macbook Pro 10上测试这一点;生产服务器要大得多。我正在与之交谈的数据库背后是一个速度极慢的VPN。我使用Oracle的Javase1.8JVM运行所有这些。本地服务器是Tomcat7。Oracle JDBC驱动程序是10.2版(我也许能够说服那些使用较新版本的能力)。所有方法要么返回void要么返回future<>并且应该是非阻塞的。

当一个批处理成功终止时,就没有问题了--下一个批处理立即开始,并满员。但是,如果我通过JobManager#Completion.TryFailure(新的CancellationException(“批处理已取消”))终止当前批处理,则Workers注册的OnFailure回调会触发,然后系统变得没有响应。调试打印指示新批处理从八个正常工作的工作者中的三个开始,并且BatchManager变得完全没有响应(我添加了一个future ping 命令,该命令只返回一个future.successful(“ping”),并且也会超时)。onfailure回调在单独的线程池上执行,即使它们在执行元系统的线程池上,我也应该有足够高的max-pool-size以容纳原始的JobManager、它的workers、它的onfailure回调,以及第二个JobManager和是workers。相反,我似乎可以容纳原始的JobManager及其Workers、新的JobManager及其不到一半的Workers以及BatchManager。我正在运行的计算机资源不足,但似乎应该能够运行十几个线程。

这是配置问题吗?这是由于JVM施加的限制和/或Tomcat施加的限制造成的吗?这是由于我处理阻塞IO的方式有问题吗?可能还有其他几件事我可能做错了,这些就是我想到的。

CancellableStatement的要点,其中CallableStatementOracleConnection被取消

创建cancellablestatements时的不可变要点

编辑:我相信我已经将问题缩小到了actor系统(或者是它的配置,或者是它与阻塞数据库调用的交互)。我消除了worker执行元,并将其工作负载移到在固定大小的ThreadPoolExecutor上执行的Runnable,其中每个JobManager创建自己的ThreadPoolExecutor并在批处理完成时关闭它(正常终止时Shutdown;异常终止时ShutdownNow)。取消在BatchManager中实例化的缓存线程池上运行。actor系统的调度器仍然是ThreadPoolExecutor,但只分配了六个线程。使用此替代设置,取消将按预期执行-当终止其数据库连接时,工作程序终止,新的JobManager立即执行,并使用完整的工作程序线程。这表明这不是硬件/JVM/Tomcat问题。

更新:我使用Eclipse的内存分析器进行了线程转储。我发现取消线程挂在CallableStatement.Close()上,因此我对取消重新排序,使OracleConnection.Abort()CallableStatement.Cancel()之前,这就解决了问题--取消全部(显然)正确执行。虽然worker线程继续挂起它们的语句--我怀疑我的VPN可能部分或全部要为此负责。

PerformanceAsync-akka.actor.default-dispatcher-19
  at java.net.SocketInputStream.socketRead0(Ljava/io/FileDescriptor;[BIII)I (Native Method)
  at java.net.SocketInputStream.read([BIII)I (SocketInputStream.java:150)
  at java.net.SocketInputStream.read([BII)I (SocketInputStream.java:121)
  at oracle.net.ns.Packet.receive()V (Unknown Source)
  at oracle.net.ns.DataPacket.receive()V (Unknown Source)
  at oracle.net.ns.NetInputStream.getNextPacket()V (Unknown Source)
  at oracle.net.ns.NetInputStream.read([BII)I (Unknown Source)
  at oracle.net.ns.NetInputStream.read([B)I (Unknown Source)
  at oracle.net.ns.NetInputStream.read()I (Unknown Source)
  at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1()S (T4CMAREngine.java:1109)
  at oracle.jdbc.driver.T4CMAREngine.unmarshalSB1()B (T4CMAREngine.java:1080)
  at oracle.jdbc.driver.T4C8Oall.receive()V (T4C8Oall.java:485)
  at oracle.jdbc.driver.T4CCallableStatement.doOall8(ZZZZ)V (T4CCallableStatement.java:218)
  at oracle.jdbc.driver.T4CCallableStatement.executeForRows(Z)V (T4CCallableStatement.java:971)
  at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout()V (OracleStatement.java:1192)
  at oracle.jdbc.driver.OraclePreparedStatement.executeInternal()I (OraclePreparedStatement.java:3415)
  at oracle.jdbc.driver.OraclePreparedStatement.execute()Z (OraclePreparedStatement.java:3521)
  at oracle.jdbc.driver.OracleCallableStatement.execute()Z (OracleCallableStatement.java:4612)
  at com.util.CPProcExecutor.execute(Loracle/jdbc/OracleConnection;Ljava/sql/CallableStatement;Lcom/controller/BaseJobRequest;)V (CPProcExecutor.java:57)

然而,即使在修复了取消顺序之后,我仍然存在actor系统没有创建足够的线程的问题:在新批处理中,我仍然只能获得8个工作者中的3个,并且由于被取消的工作者的网络连接超时,还会添加新的工作者。总共我有11个线程--我的核心池大小,在29个线程中--我的最大池大小。显然,执行元系统忽略了我的最大池大小参数,或者我没有正确配置最大池大小。

共有1个答案

翁建弼
2023-03-14

(免责声明:我不认识Akka)

根据您下面的queue-size=-1配置,我猜任务队列是无界的。

  "task-queue-size": "-1",
  "task-queue-type": "linked"

除非工作队列已满且无法排队,否则ThreadPoolExecutor不会生成超出核心池大小的内容。只有当任务队列已满时,它才会开始生成最多的线程。

 类似资料:
  • 当我们用来谈论核心池大小和最大池大小之间的区别到底是什么? 可以借助示例来解释吗?

  • 主要内容:1 execute核心提交方法,2 addWorker尝试添加新线程,2.1 addWorkerFailed添加Worker失败处理,3 Worker线程包装类,3.1 runWorker执行工作基于JDK1.8详细介绍了ThreadPoolExecutor线程池的execute方法源码! 1 execute核心提交方法 public void execute(Runnable command) 传递一个Runnable任务对象,然后由线程池对它进行异步执行。没有办法检查Runnabl

  • 自定义线程池的建议大小是number_of_cores+1(请参见此处和此处)。假设有一个Spring应用程序在一个系统上有两个核心,配置如下所示 在这种情况下,将有一个ExecutorService在几个请求之间共享。因此,如果有10个请求到达服务器,那么在ExecutorService中只能同时执行其中的3个请求。这可能会产生瓶颈,并且随着请求数量的增加,结果会变得更糟(请记住:默认情况下,t

  • 问题内容: 许多次我听说最好将线程池中的线程数保持在该系统中的内核数以下。具有比核心数多两倍或更多的线程不仅浪费,而且还可能导致性能下降。 那些是真的吗?如果不是,那么揭露这些主张的基本原则是什么(特别是与Java有关)? 问题答案: 许多次我听说最好将线程池中的线程数保持在该系统中的内核数以下。具有比核心数多两倍或更多的线程不仅浪费,而且还可能导致性能下降。 这些主张 作为一般性陈述 是不正确的

  • 我对为什么以下演员不起作用感到非常困惑: schduledThreadPoolExector实现了schduledExecutorService。如果我不能将它与实际的类一起使用,这个执行器调用的意义是什么? 我用错了吗(可能),有人能提供一些指导吗?

  • 我需要帮助设计基于多线程的应用程序,包括动态url创建和线程处理。 我在我的应用程序中使用了一个Spring调度器,它每30秒调度一次。从这个调度方法中,我调用了一些基于服务的api,它在循环中,而且我需要每个API有一个线程池执行器,上面有一个线程处理。 由于这个过程是从计划方法开始的,所以每次创建新的线程池时,这就是问题所在。你可以在代码中看到。 我想要的是,如果对于任何一个应用编程接口,如果