web-dev-qa-db-ja.com

JEE6 @ApplicationScopedBeanと並行性

アクセスされた回数のカウンターとして機能するBeanを作成する必要があります。

@ApplicationScopedbeanを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の状態が変更された場合は、同時実行アノテーションとロックを使用する必要があると言われていますが、リストでスレッドセーフがすでに処理されている場合はどうなりますか?

23
grafthez

CDIには同時実行管理がないため、_@ApplicationScoped_は、注入されたオブジェクトのカーディナリティを示すだけです(つまり、注入エンジンにBeanのインスタンスを1つだけ作成し、それをすべてのアプリケーションで使用するように指示します)。これは、EJBでBeanを変換せず、並行性の制約を強制しません。

したがって、例の操作は本質的にスレッドセーフですが、AtomicIntegerと同期リストのおかげで、一般的に同じことは当てはまりません。

一般的に、次のことができます。

  • 標準の同時実行プリミティブを介してリストアクセスを手動で同期します(これまでに行ったように)

  • または、_javax.ejb.Singleton_アノテーションを使用して、同時実行を管理するようにアプリケーションサーバーに指示します。これにより、EJBでBeanが変換され、デフォルトで@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)@Lock(LockType.WRITE)が適用されます。

ちなみに、_@ConcurrencyManagement_と_@Lock_はシングルトンセッションBeanでのみ使用できます。

37