Wildfly 10:尝试实现 Java 并发实用程序时出错

Posted

技术标签:

【中文标题】Wildfly 10:尝试实现 Java 并发实用程序时出错【英文标题】:Wildfly 10: Error trying to implement Java Concurrency Utilities 【发布时间】:2019-07-11 15:36:50 【问题描述】:

我希望有人可以提供帮助,因为我在这里迷路了。 我正在尝试使用线程在我们的 Web 应用程序中创建一些报告。我们的应用程序使用 wildfly-10-final、postgresql、zk 框架和 ejb3。 我按照这个示例here 创建线程。

我在无状态服务中创建了这个函数:

@Override
public void runTask(Runnable task)
    executorService.execute(task);
    try 
        semaphore.tryAcquire(20, TimeUnit.MINUTES);
     catch (InterruptedException e) 
        e.printStackTrace();
    

我使用这一行来调用 ManagedExecutorService:

@Resource
private ManagedExecutorService executorService;

domain-clustered.xml里面有这个配置:

<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>

这个函数是从视图模型中调用的。 在我运行应用程序之前,一切似乎都很好。 - 我首先收到此错误:

[Server:integration] 12:03:30,071 错误 [org.jboss.as.ejb3.timer](EJB 默认 - 3)WFLYEJB0020:为计时器调用超时错误:[id=3425f89c-802f-4203-b74e- b64446015242 timedObjectId=integration.kernel.RmtModule auto-timer?:false persistent?:false timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@194a63bb initialExpiration=Mon Feb 18 12:02:16 AST 2019 intervalDuration(毫秒)=1000 nextExpiration=Mon Feb 18 12:03:31 AST 2019 timerState=IN_TIMEOUT info=it.tecnositaf.rmt3.kernel.common.modules.scheduler.RMTTimerConfig@55f179c7]: javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0241: EJB 3.1 PFD2 4.8.5.5.1 RmtModule 上的并发访问超时 - 无法在 60000MILLISECONDS 内获得锁 [服务器:集成]在 org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:106) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成] 在 org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成]在 org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成]在 org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成] 在 org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) [服务器:集成] 在 org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:636) [服务器:集成]在 org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) [服务器:集成]在 org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80) [服务器:集成] 在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:集成]在 org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) [服务器:集成] 在 org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:99) [服务器:集成] 在 org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:109) [服务器:集成]在 org.jboss.as.ejb3.timerservice.TimerTask.invokeBeanMethod(TimerTask.java:190) [服务器:集成] 在 org.jboss.as.ejb3.timerservice.TimerTask.callTimeout(TimerTask.java:186) [服务器:集成] 在 org.jboss.as.ejb3.timerservice.TimerTask.run(TimerTask.java:157) [服务器:集成] 在 org.jboss.as.ejb3.timerservice.TimerServiceImpl$Task$1.run(TimerServiceImpl.java:1215) [服务器:集成] 在 org.wildfly.extension.requestcontroller.RequestController$QueuedTask$1.run(RequestController.java:497) [服务器:集成] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [服务器:集成] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [服务器:集成] 在 java.lang.Thread.run(Thread.java:745) [Server:integration] at org.jboss.threads.JBossThread.run(JBossThread.java:320)

在此之后我不断收到此错误:

[Server:business] 12:04:25,757 错误 [org.jboss.as.ejb3.timer](EJB 默认值 - 50)WFLYEJB0022:重试计时器超时期间出错:[id=9e890d13-77fa-4135-a0d8 -41c1c5318800 timedObjectId=business.kernel.RmtModule auto-timer?:false persistent?:false timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@3782910b initialExpiration=2019 年 2 月 18 日星期一 12:02:23 AST 2019 间隔时间(单位为毫sec)=1000 nextExpiration=Mon Feb 18 12:04:26 AST 2019 timerState=RETRY_TIMEOUT info=it.tecnositaf.rmt3.kernel.common.modules.scheduler.RMTTimerConfig@2568f194]: javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0241: EJB 3.1 PFD2 4.8.5.5.1 RmtModule 上的并发访问超时 - 无法在 60000MILLISECONDS 内获得锁定 [服务器:业务]在 org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:106) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [Server:business] at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) [服务器:企业] 在 org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:636) [服务器:业务]在 org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) [服务器:业务]在 org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80) [服务器:业务]在 org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) [服务器:业务]在 org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:99) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimedObjectInvokerImpl.callTimeout(TimedObjectInvokerImpl.java:109) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimerTask.invokeBeanMethod(TimerTask.java:190) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimerTask.callTimeout(TimerTask.java:186) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimerTask.retryTimeout(TimerTask.java:213) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimerTask.run(TimerTask.java:165) [服务器:业务]在 org.jboss.as.ejb3.timerservice.TimerServiceImpl$Task$1.run(TimerServiceImpl.java:1215) [服务器:业务] 在 org.wildfly.extension.requestcontroller.RequestController$QueuedTask$1.run(RequestController.java:497) [服务器:业务] 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [服务器:业务] 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [服务器:业务] 在 java.lang.Thread.run(Thread.java:745) [Server:business] at org.jboss.threads.JBossThread.run(JBossThread.java:320)

这是我第一次在 wildfly 和 java ee 容器中处理线程,所以我不知道是什么原因造成的。

【问题讨论】:

【参考方案1】:

这里有点猜测,因为我不知道 wildfly 是什么,但是从您的 Async Servlets 链接看来,您可能正在使用 0-permit 信号量来向您的任务发出信号,结果已准备就绪。如果您的 Runnable 使用共享(字段,而不是局部变量)信号量,则可能与为每个任务创建信号量并从不同的 .release()d 传递到任务中的相同模式线。 这种实现方式很可能会被破坏,例如任务线程指示错误的提交者线程继续并检索结果!从这里它可能会爆炸并且无法释放 EJB 并发锁。

现在,假设实际情况并非如此,即任务向正确的提交者发出信号,而不是信号量上阻塞的随机线程。 实际异常必须来自 boolean success = lock.tryLock(time, unit); if (!success) throw EjbLogger.ROOT_LOGGER.concurrentAccessTimeoutException(invocationContext, time + unit.name()); (摘自ContainerManagedConcurrencyInterceptor.java) 在上述假设下,您的任务是否可能长时间运行,因此 60 秒超时还不够?如果您分享任务正在做什么(以及持续多长时间)的详细信息,可能会有所帮助。

【讨论】:

感谢您的回答。事实上,我使用的是 0-permit 信号量,就像示例中的信号量一样。它从服务传递到视图模型,然后从那里传递到任务。但我怀疑是信号量引发了异常。我的第一个实现是没有使用信号量,但我仍然遇到同样的错误。 对于任务,它们包括从数据库读取和写入。从数据库中读取历史数据并生成报告文件,将其保存在目录中,然后将其记录到数据库中。数据可能从几条记录到数千条不等。 好的,这很好(信号量可能不会因为在不应该共享的地方而搞砸)。如果只是您的任务花费的时间太长,那么将超时时间增加到几分钟怎么样,也许是 20,就像在基于信号量的等待中一样?我假设它是hung-task-threshold="60000",但可能是错误的 - 使它成为 20 倍。如果异常一直说 60000MILLISECONDS,则在其他地方指定。这可能是解决这个问题的最佳方法,但另一个探索的途径是将任务分解成更小的部分。这要复杂得多。

以上是关于Wildfly 10:尝试实现 Java 并发实用程序时出错的主要内容,如果未能解决你的问题,请参考以下文章

为啥在建立 httpSession 后 Wildfly 服务器不能处理并发 REST 请求

Java Semaphore实现高并发场景下的流量控制(附源码) | 实用代码架构

Wildfly 10.1.0 - 未找到 Mysql 数据源

无法在 Wildfly 10 上定义 oracle 数据源

Wildfly 忽略 ApplicationPath

麒麟服务器V10 SP1 安装JBOSS-wildfly