JEE6 @ApplicationScoped bean 和并发

Posted

技术标签:

【中文标题】JEE6 @ApplicationScoped bean 和并发【英文标题】:JEE6 @ApplicationScoped bean and concurrency 【发布时间】:2012-12-23 15:14:13 【问题描述】:

我需要编写一个 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的状态发生修改时应该使用并发注解和锁,但是如果我的列表已经照顾了线程安全呢?

【问题讨论】:

实施后,我没有看到任何并发问题。 【参考方案1】:

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

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

一般来说你可以:

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

或者使用javax.ejb.Singleton注解,指示应用服务器管理并发。这会将您的 bean 转换为 EJB,默认情况下强制执行 @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)@Lock(LockType.WRITE)

顺便说一下,@ConcurrencyManagement@Lock 仅适用于单例会话 bean。

【讨论】:

好一个。我在想如果我将@ApplicationScoped bean 注入@Stateful EJB 会发生什么,看起来你可能会遇到问题,因为你可以从 EJB 的 2 个实例中修改相同的数据。 字段(countervalues)是否保证可见?毕竟它们是由不同的线程访问的,没有任何并发​​机制。

以上是关于JEE6 @ApplicationScoped bean 和并发的主要内容,如果未能解决你的问题,请参考以下文章

JavaEE6 DAO:应该是@Stateless 还是@ApplicationScoped?

多次构造 Eager ApplicationScoped 托管 bean

@ApplicationScoped JSF 托管 bean 的并发性

授权过滤器中的错误(JEE6)

JEE6 中的 Websocket

@ApplicationScoped CDI bean 和 @PersistenceContext - 这安全吗?