Java 无响应的参与者系统:ThreadPoolExecutor dispatcher只创建核心线程池,显然忽略了最大线程池大小
更新:我发现,如果我将Java 无响应的参与者系统:ThreadPoolExecutor dispatcher只创建核心线程池,显然忽略了最大线程池大小,java,multithreading,scala,akka,blocking,Java,Multithreading,Scala,Akka,Blocking,更新:我发现,如果我将ThreadPoolExecutor的核心池大小设置为与最大池大小(29个线程)相同,我的程序将保持响应。但是,如果我将核心池大小设置为11,将最大池大小设置为29,那么actor系统只创建11个线程。如何配置ActorSystem/ThreadPoolExecutor继续创建线程以超过核心线程数并保持在最大线程数内?我不希望将核心线程数设置为最大线程数,因为我只需要额外的线程来取消作业(这应该是一个罕见的事件) 我有一个针对Oracle数据库运行的批处理程序,使用Jav
ThreadPoolExecutor的
核心池大小设置为与最大池大小(29个线程)相同,我的程序将保持响应。但是,如果我将核心池大小设置为11,将最大池大小设置为29,那么actor系统只创建11个线程。如何配置ActorSystem/ThreadPoolExecutor
继续创建线程以超过核心线程数并保持在最大线程数内?我不希望将核心线程数设置为最大线程数,因为我只需要额外的线程来取消作业(这应该是一个罕见的事件)
我有一个针对Oracle数据库运行的批处理程序,使用Java/Akka类型的参与者和以下参与者实现:
BatchManager
负责与REST控制器对话。它管理未初始化的批处理作业的队列
;当从队列轮询未初始化的批处理作业时,它将变为JobManager
actor并执行JobManager
维护一个存储过程队列和一个工作者池
;它用一个存储过程初始化每个工作者
,当工作者
完成时,它将过程的结果发送给作业管理器
,而作业管理器
将另一个存储过程发送给工作者
。当作业队列为空且所有worker
空闲时,批处理终止,JobManager
将其结果报告给BatchManager
,关闭其worker(通过TypedActor.context().stop()
),然后关闭自身。JobManager
具有一个承诺完成
,当作业成功完成时,或者当作业因取消或致命异常而终止时,该承诺完成Worker
执行存储过程。它创建用于执行存储过程的和,并向JobManager.completion
注册onFailure
回调以abort
连接和cancel
语句。此回调不使用actor系统的执行上下文,而是使用从BatchManager
中创建的缓存执行器服务创建的执行上下文{"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=8
coreActorCount
是workerCount+3
而maxActorCount
是workerCount*3+5
。我正在一台有两个内核和8GB内存的MacBookPro 10上进行测试;生产服务器要大得多。我正在谈论的数据库是在一个非常慢的VPN后面。我使用Oracle的JavaSE 1.8 JVM运行所有这些。本地服务器是Tomcat7。Oracle JDBC驱动程序的版本是10.2(我可能能够说服那些使用更新版本的超级用户)。所有方法要么返回void
要么返回Future
并且应该是非阻塞的
当一个批次成功终止时,则没有问题-下一个批次立即开始,并有完整的工人。但是,如果我通过JobManager#completion.tryFailure(新取消异常(“批取消”))
终止当前批处理,则工作人员注册的onFailure
回调将触发,然后系统将变得无响应。Debug PRINTLN表明新批处理从八分之三的正常工作人员开始,并且BatchManager
变得完全无响应(我添加了一个Future ping
命令,该命令只返回一个Futures.successful(“ping”)
,这也会超时)。onFailure
回调在一个单独的线程池上执行,即使它们在actor系统的线程池上,我也应该有足够高的最大池大小
,以容纳原始的JobManager
、其工作人员
、其onFailure
回调,第二个是JobManager
,是Workers
。相反,我似乎在适应原来的JobManager
及其工作人员
,新的JobManager
及其不到一半的工作人员
,而BatchManager没有剩余的东西。
我运行此功能的计算机资源不足,但它似乎应该能够运行十几个线程
这是配置问题吗?这是由于JVM施加的限制和/或Tomcat施加的限制造成的吗?这是因为我如何处理阻塞IO的问题吗?我可能还有其他几件事做错了,这些正是我想到的
其中,CallableStatement
和OracleConnection
被取消
其中创建了cancelablestatements
通过System.out.println(mergedConfig.toString())获取代码>
编辑:我相信我已经将问题缩小到了actor系统(它的配置或与阻止数据库调用的交互)。我消除了工作者
参与者,并将他们的工作负载移动到在固定大小的ThreadPoolExecutor
上执行的Runnables
,其中每个JobManager
创建自己的ThreadPoolExecutor
,并在批处理完成时关闭它(正常终止时关闭
,异常终止时关闭
).Cancellation在BatchManager
中实例化的缓存线程池上运行。actor系统的dispatcher仍然是ThreadPoolExecutor
,但只有六个线程分配给它。使用此替代设置,Cancellation按预期执行-w
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)
SELECT s1.username || '@' || s1.machine
|| ' ( SID=' || s1.sid || ' ) is blocking '
|| s2.username || '@' || s2.machine || ' ( SID=' || s2.sid || ' ) ' AS blocking_status
FROM v$lock l1, v$session s1, v$lock l2, v$session s2
WHERE s1.sid=l1.sid AND s2.sid=l2.sid
AND l1.BLOCK=1 AND l2.request > 0
AND l1.id1 = l2.id1
AND l1.id2 = l2.id2
"task-queue-size": "-1",
"task-queue-type": "linked"