JEE6 @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 values; @PostConstruct public void construct() { values = Collections.synchronizedList(new LinkedList()); } 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。