调用self时,EJB Singleton WRITE锁不受尊重

时间:2017-04-03 20:37:07

标签: java java-ee concurrency singleton ejb

我将此EJB部署到Glassfish 4(Java EE 7):

import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Singleton;

@Singleton
@Lock(LockType.WRITE) // WRITE is default, but here for emphasis
public class SingletonBean {

    @EJB
    SingletonBean self;

    @Schedule(second="*/3", minute="*", hour="*")
    public void test_automatic_timer() throws InterruptedException {
        System.out.println("test_automatic_timer()");
        self.test();
    }

    public void test() {
        System.out.println("test()");
    }

}

我预计这会陷入僵局。当计时器调用test_automatic_timer时,它获得WRITE锁。对self.test()的调用应该永远等待锁定被释放,但是在日志中我有:

Info:   test_automatic_timer()
Info:   test()
Info:   test_automatic_timer()
Info:   test()

为什么这不按我预期的方式工作?

P.S。这不完全是学术性的。我想进行self调用,以便获得a new container-managed transaction,但我想确保首先更好地理解同步。

确认史蒂夫的回答

史蒂夫的回答是正确的。为了确认这一点,我记录了线程ID并看到它们是相同的。我还想确认锁是否正常工作,所以我重写了方法体,如下所示:

@Schedule(second="*/3", minute="*", hour="*")
public void test_automatic_timer() throws InterruptedException {
    System.out.println("test_automatic_timer()");
    System.out.println(Thread.currentThread());
    self.test();
    Thread.sleep(10_000);
}

@Asynchronous
public void test() {
    System.out.println("test()");
    System.out.println(Thread.currentThread());
}

如果这按预期工作,对test的异步调用将被阻止十秒钟,直到test_automatic_timer完成。如果它不起作用,test将立即执行。日志显示:

Info:   test_automatic_timer()
Info:   Thread[__ejb-thread-pool11,5,main]
// 10 second pause...
Info:   test()
Info:   Thread[__ejb-thread-pool12,5,main]

所以它有效。

1 个答案:

答案 0 :(得分:1)

此代码不会死锁,因为test()的调用是在同一个(定时器执行)线程中进行的。

那就是说我认为至少有一些自我注入像这样的单身的行为可能是未定义的。如果您引入引用@PostConstruct的{​​{1}}方法,会发生什么?

你的bean名称用词不当,因为self bean是有状态的。

无论如何,做以下事情可能更安全:

@Singleton

这确实是使用新事务自我调用EJB的方法。