java JEE6 @ApplicationScoped bean 和并发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14237499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:34:28  来源:igfitidea点击:

JEE6 @ApplicationScoped bean and concurrency

javajakarta-eeconcurrencycdi

提问by grafthez

I need to write a bean that would act as a counter of how many times it was accessed.

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

I'm thinking of using @ApplicationScopedbean with AtomicIntegerlike that

我想使用的@ApplicationScoped豆有AtomicInteger这样的

@ApplicationScoped
class VisitsCounter {

    private AtomicInteger counter;

    @PostConstruct
    public void construct() {
        counter = new AtomicInteger(0);
    }

    public int visited() {
        return counter.incrementAndGet();
    }
}

My question is: is it ok when considering multiple requests at the same time? Or do i need to play with @ConcurrencyManagementand @Lockannotations? I suppose that Atomic*should do the trick but I'm not sure.

我的问题是:同时考虑多个请求是否可以?还是我需要玩@ConcurrencyManagement@Lock注释?我想这Atomic*应该可以解决问题,但我不确定。

Also does the same applies when I have thread safe collections as a fields? E.g. say I have

当我将线程安全集合作为字段时,这也同样适用吗?例如说我有

@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);
    }
}

are the operations really thread-safe?

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

It is said that concurrency annotations and locks should be used when there is modification of state of the bean, but what if my list already takes care of thread safety?

据说当bean的状态被修改时应该使用并发注解和锁,但是如果我的列表已经处理了线程安全呢?

回答by Carlo Pellegrini

In CDI you don't have concurrency management, so @ApplicationScopedsimply states the cardinality of the injected object (i.e. instructs the injection engine to create only one instance of your bean and use it across all the application). It does not transform your bean in an EJB, and does not enforce any concurrency constraint.

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

So, while the operations in the examples are inherently thread safe, thanks to the AtomicIntegerand the synchronized list, the same is not true in general.

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

In the general you can:

一般来说,您可以:

  • manually synchronize the list accesses through the standard concurrency primitives (as you have done)

  • or use the javax.ejb.Singletonannotation, which instructs the application server to manage concurrency. This transforms your bean in an EJB and by default enforces @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)and @Lock(LockType.WRITE).

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

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

By the way, @ConcurrencyManagementand @Lockare only available on singleton session beans.

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