在我的 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 用于计时器方法时,不会发生死锁。但为什么?异步方法调用什么?