DEADLOCK,EJB 3.1,在Singleton中使用异步方法和TimerService

时间:2010-08-16 12:46:14

标签: asynchronous java-ee deadlock ejb-3.1

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

1 个答案:

答案 0 :(得分:0)

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

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