2

在我的 Singleton-EJB 中,我每 2 分钟启动一次 TimerService。当客户端访问测试方法时,应用程序有时会陷入死锁。问题是,测试方法调用 EJB 内部的异步方法(请参阅 Method determineABC)。当scheduleMethod尝试创建单个操作计时器并因此尝试获取锁时,就会发生死锁(因为 hte 计时器回调方法使用 LOCK.WRITE 进行了注释)。同时,我们已经在尝试调用异步方法asynchMethod的determineABC方法中。也许是ejbLocal.asynchMethod(...);的调用还尝试获取锁。无论如何,我在这里遇到了死锁,因为从不调用异步方法。那么问题是什么?

这是一个源代码片段:

@Singleton
@Startup
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class XEJB implements XEJBLocal {

@javax.annotation.Resource(name = "x/XEJB/TimeService")
private TimerService timerService;
@javax.annotation.Resource
private SessionContext ctx;

@Schedule(minute = "*/2", hour = "*", persistent = false)
@Lock(LockType.READ)
private void scheduleMethod() {
    // Create Single Action Timer
    timerService.createSingleActionTimer(new Date(), new TimerConfig(null, false));
}

@Timeout
@Lock(LockType.WRITE)
private void timer(Timer timer) {
   // Do something
}

@Override
@Lock(LockType.READ)
public B test(...)  {
    return determineABC(...);
}

@Lock(LockType.READ)
private B determineABC(...) {
    XEJBLocal ejb= (XEJBLocal)  ctx.getBusinessObject(ctx.getInvokedBusinessInterface());
    Future<ArrayList> result = null;
    result = ejb.asynchMethod(...);
    result.get(4, TimeUnit.MINUTES);  // Sometimes runs into a DEADLOCK
    ...
}

@Asynchronous
@Override
@Lock(LockType.READ)
public Future<ArrayList> asynchMethod(...) {
    ...
    return new AsyncResult<ArrayList>(abcList);
}

当我只使用@Schedule方法而不使用TimerService时也会发生死锁......当我不使用 Future 对象但 void 作为异步方法的返回类型时也会发生死锁。

当抛出超时异常时,死锁就解决了。当我用@AccessTimeout(2000)注释计时器方法并且这个时间结束时,调用异步方法,因此也解决了死锁。

当我将 Locktype.READ 用于计时器方法时,不会发生死锁。但为什么?异步方法调用什么?

4

1 回答 1

0

READ 锁必须等待 WRITE 锁完成才能开始工作。当 timer() 工作时,所有其他调用,甚至是 READ 方法,都将等待。你确定超时发生在result.get(4, TimeUnit.MINUTES);

我认为您可能在 test() 调用中访问超时,在到达之前的方式result.get(4, TimeUnit.MINUTES);

于 2014-11-07T16:26:46.540 回答