Подтвердить что ты не робот

JEE6 @ApplicationScoped bean и concurrency

Мне нужно написать 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);
    }
}

Действительно ли операции действительно потокобезопасны?

Говорят, что concurrency аннотации и блокировки должны использоваться при изменении состояния bean, но что, если мой список уже заботится о безопасности потоков?

4b9b3361

Ответ 1

В CDI у вас нет управления concurrency, поэтому @ApplicationScoped просто задает мощность введенного объекта (т.е. инструктирует движок инъекции создать только один экземпляр вашего bean и использовать его во всех приложениях). Он не преобразует ваш bean в EJB и не применяет ограничение concurrency.

Итак, хотя операции в примерах по сути являются потокобезопасными, благодаря AtomicInteger и синхронизированному списку, в общем случае это не так.

В общем вы можете:

  • вручную синхронизировать доступ к списку через стандартные примитивы concurrency (как вы это сделали)

  • или используйте аннотацию javax.ejb.Singleton, которая указывает серверу приложений управлять concurrency. Это преобразует ваш bean в EJB и по умолчанию обеспечивает выполнение @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) и @Lock(LockType.WRITE).

Кстати, @ConcurrencyManagement и @Lock доступны только на одноэлементном сеансе beans.