@ApplicationScoped bean和并发性



我需要编写一个bean,它将作为访问次数的计数器。

我正在考虑使用@ApplicationScoped bean与AtomicInteger像这样

@ApplicationScoped
class VisitsCounter {
    private AtomicInteger counter;
    @PostConstruct
    public void construct() {
        counter = new AtomicInteger(0);
    }
    public int visited() {
        return counter.incrementAndGet();
    }
}

我的问题是:在同一时间考虑多个请求是可以的吗?或者我需要玩@ConcurrencyManagement@Lock注释?我想Atomic*应该能做到这一点,但我不确定。

也同样适用于当我有线程安全的集合作为一个字段?例如,我有

@ApplicationScoped
class ValuesHolder {
    private List<String> values;
    @PostConstruct
    public void construct() {
        values = Collections.synchronizedList(new LinkedList<String>());
    }
    public void insert(String value) {
        values.add(value);
    }
    public String remove(String value) {
        return values.remove(value);
    }
}

操作真的是线程安全的吗?

据说并发注释和锁应该在修改bean状态时使用,但是如果我的列表已经考虑到线程安全怎么办?

在CDI中,你没有并发管理,所以@ApplicationScoped只是声明被注入对象的基数(即指示注入引擎只创建一个bean实例并在所有应用程序中使用它)。它不会在EJB中转换bean,也不会强制执行任何并发性约束。

因此,尽管示例中的操作本质上是线程安全的,但由于AtomicInteger和同步列表,通常情况下并非如此。

一般情况下可以:

  • 通过标准并发原语手动同步列表访问(如您所做的)

  • 或使用javax.ejb.Singleton注释,它指示应用程序服务器管理并发性。这将转换EJB中的bean,并在默认情况下强制执行@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)@Lock(LockType.WRITE)

顺便说一下,@ConcurrencyManagement@Lock只在单例会话bean上可用。

最新更新