在我的Singleton-EJB中,我每2分钟启动一次TimerService。当客户端访问测试方法时 有时应用程序会遇到死锁。问题是, test 方法在EJB内部调用异步方法(请参阅方法 determineABC )。当 scheduleMethod 尝试创建单个操作计时器并因此尝试获取锁时(因为hte计时器回调方法使用LOCK.WRITE注释),就会发生死锁。与此同时,我们已经在 determineABC 方法中尝试调用异步方法 asynchMethod 。也许 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 Object但是void作为异步Method的返回类型时,也会发生DeadLock。
当抛出超时异常时,解决了死锁。当我使用 @AccessTimeout(2000)注释 timer 方法时,此时间已启动,异步方法被调用,因此死锁也已解决。
当我使用Locktype.READ作为计时器方法时,不会发生死锁。但为什么?什么是异步方法调用?
答案 0 :(得分:0)
READ锁必须等待WRITE锁完成才能开始工作。当timer()工作时,所有其他的调用,甚至是READ方法,都会等待。你确定result.get(4, TimeUnit.MINUTES);
发生了超时吗?
我认为您可能会在到达result.get(4, TimeUnit.MINUTES);
之前的test()调用中访问超时。