Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java TomEE阻塞了太多@Asynchronous操作_Java_Asynchronous_Ejb_Apache Tomee - Fatal编程技术网

Java TomEE阻塞了太多@Asynchronous操作

Java TomEE阻塞了太多@Asynchronous操作,java,asynchronous,ejb,apache-tomee,Java,Asynchronous,Ejb,Apache Tomee,我正在使用ApacheTomee1.5.2JAX-RS,几乎是开箱即用的,带有预定义的HSQLDB 下面是简化的代码。我有一个REST风格的接口用于接收信号: @Stateless @Path("signal") public class SignalEndpoint { @Inject private SignalStore store; @POST public void post() { store.createSignal();

我正在使用ApacheTomee1.5.2JAX-RS,几乎是开箱即用的,带有预定义的HSQLDB

下面是简化的代码。我有一个REST风格的接口用于接收信号:

@Stateless
@Path("signal")
public class SignalEndpoint {
    @Inject
    private SignalStore store;

    @POST
    public void post() {
        store.createSignal();
    }
}
收到信号会触发很多事情。存储将创建一个实体,然后触发一个异步事件

public class SignalStore {
    @PersistenceContext
    private EntityManager em;

    @EJB
    private EventDispatcher dispatcher;

    @Inject
    private Event<SignalEntity> created;

    public void createSignal() {
        SignalEntity entity = new SignalEntity();
        em.persist(entity);
        dispatcher.fire(created, entity);
    }
}
这就好像托米不会做任何排队的操作。如果在调用的那一刻没有线程可以自由处理,那就太倒霉了。当然,这不是故意的

更新2:

好的,我似乎偶然发现了一个半解决方案:将
AsynchronousPool.QueueSize
属性设置为maxint可以解决冻结问题。但问题仍然存在:首先,为什么队列大小如此有限,更令人担忧的是:为什么这会阻止整个应用程序?如果队列已满,它会阻塞,但一旦从队列中取出一个任务,就会弹出另一个任务,对吗?队列似乎已被阻止,直到它再次完全为空

更新3:

对于任何想尝试的人:

更新4:

事实证明,增加队列大小并不能解决问题,只会延迟问题。问题仍然是一样的:一次有太多的异步操作,而且TOME阻塞非常严重,以至于它甚至无法在终止时取消部署应用程序

到目前为止,我的诊断是任务清理无法正常工作。我的任务都非常小且快速(请参阅)。我已经担心OpenJPA或HSQLDB会在太多并发调用上减慢速度,但我注释掉了所有
em.persist
调用,问题依然存在。因此,如果我的任务非常小且速度很快,但仍然设法阻止了我,以至于它在30秒后无法获得任何进一步的任务(
javax.ejb.EJBException:fail-allocation internal resource to execute目标任务
),我会想象完成的任务会被拖延,可以说阻塞了管道


如何解决此问题?

基本上,阻塞队列使用锁来确保数据的一致性并避免数据丢失,因此在高度并发的环境中,它将拒绝许多任务(您的情况)

您可以使用RejectedExecutionHandler实现在主干上播放,以重试提供任务。一种实现可以是:

new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
            for (int i = 0; i < 10; i++) {
                if (executor.getQueue().offer(r)) {
                    return;
                }

                try {
                    Thread.sleep(50);
                } catch (final InterruptedException e) {
                    // no-op
                }
            }
            throw new RejectedExecutionException();
        }
    }
new RejectedExecutionHandler(){
@凌驾
public void rejectedExecution(最终可运行r、最终线程池执行器执行器){
对于(int i=0;i<10;i++){
if(executor.getQueue().offer(r)){
返回;
}
试一试{
睡眠(50);
}捕获(最终中断异常e){
//无操作
}
}
抛出新的RejectedExecutionException();
}
}
它甚至可以更好地与随机睡眠(最小和最大之间)


其基本思想是:如果队列已满,请稍等片刻以降低并发性。

可通过WEB-INF/application.properties进行配置

您是否在JVM冻结之前对其进行了线程转储?我也遇到了同样的问题,从EventDispatcher中删除@Asynchronous,我不记得eventdispatcher为什么是异步的too@wutzebaer是的,这将解决这个问题,因为它只是删除了所有的线程池和所有导致问题的东西。我们的想法是让事件的处理不会阻止初始请求。但是观察器函数不是仍然是异步的吗?@wutzebaer是的,但是如果dispatcher方法不是异步的,那么触发所有事件处理程序仍然是同步的。可能没有那么大的影响,我同意。不管怎样,在我的书中,使这两种异步都能正常工作,没有任何奇怪的行为。非常感谢:-)像这样的处理程序也能进入TomEE本身吗?
@Stateless
public class DerivedDataCreator {
    @PersistenceContext
    private EntityManager em;

    @EJB
    private EventDispatcher dispatcher;

    @Inject
    private Event<DerivedDataEntity> created;

    @Asynchronous
    public void onSignalEntityCreated(@Observes SignalEntity signalEntity) {
        DerivedDataEntity entity = new DerivedDataEntity(signalEntity);
        em.persist(entity);
        dispatcher.fire(created, entity);
    }
}
Aug 01, 2013 3:12:31 PM org.apache.openejb.core.transaction.EjbTransactionUtil handleSystemException
SEVERE: EjbTransactionUtil.handleSystemException: fail to allocate internal resource to execute the target task
javax.ejb.EJBException: fail to allocate internal resource to execute the target task
    at org.apache.openejb.async.AsynchronousPool.invoke(AsynchronousPool.java:81)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:240)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:86)
    at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:303)
    at <<... my code ...>>
    ...
Caused by: java.util.concurrent.RejectedExecutionException: Timeout waiting for executor slot: waited 30 seconds
    at org.apache.openejb.util.executor.OfferRejectedExecutionHandler.rejectedExecution(OfferRejectedExecutionHandler.java:55)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
    at org.apache.openejb.async.AsynchronousPool.invoke(AsynchronousPool.java:75)
    ... 38 more
new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
            for (int i = 0; i < 10; i++) {
                if (executor.getQueue().offer(r)) {
                    return;
                }

                try {
                    Thread.sleep(50);
                } catch (final InterruptedException e) {
                    // no-op
                }
            }
            throw new RejectedExecutionException();
        }
    }