アクセスされた回数のカウンターとして機能する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の状態が変更された場合は、同時実行アノテーションとロックを使用する必要があると言われていますが、リストでスレッドセーフがすでに処理されている場合はどうなりますか?
CDIには同時実行管理がないため、_@ApplicationScoped
_は、注入されたオブジェクトのカーディナリティを示すだけです(つまり、注入エンジンにBeanのインスタンスを1つだけ作成し、それをすべてのアプリケーションで使用するように指示します)。これは、EJBでBeanを変換せず、並行性の制約を強制しません。
したがって、例の操作は本質的にスレッドセーフですが、AtomicInteger
と同期リストのおかげで、一般的に同じことは当てはまりません。
一般的に、次のことができます。
標準の同時実行プリミティブを介してリストアクセスを手動で同期します(これまでに行ったように)
または、_javax.ejb.Singleton
_アノテーションを使用して、同時実行を管理するようにアプリケーションサーバーに指示します。これにより、EJBでBeanが変換され、デフォルトで@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
と@Lock(LockType.WRITE)
が適用されます。
ちなみに、_@ConcurrencyManagement
_と_@Lock
_はシングルトンセッションBeanでのみ使用できます。