1

私は@ApplicationScopedすべてのユーザー用のBeanを持っています。これは、ids->名前とその逆をTrove&java.utilマップに保存します。

Bean の構築時または (Web サイト管理者による手動更新の場合)マップを一度だけ構築します。

Bean メソッド内ではget()、マップで を使用しているだけなので、マップは変更しません。準備が整った目的でのみ使用されるため、これはスレッドセーフになりますか? 私はマップを外部の他の Bean と共有しておらず、コード内でいつでもマップを変更 (エントリの追加/削除) していません。

また、この場合、フィールドを final にする必要がありますか?

Bean コードは次のとおりです。

@ApplicationScoped
@ManagedBean(name="directory", eager=true)
public class directory {

    private static TIntObjectHashMap<String> idsToNamesMap;
    private static TreeMap<String, Integer> namesToIdsMap;

    @PostConstruct
    public void buildDirectory(){
        // building directory here ....
    }

    public String getName(int topicId){
        return idsToNamesMap.get(topicId);
    }    

    public List<Entry<String, Integer>> searchTopicsByName(String query){
        return new ArrayList(namesToIdsMap.subMap(query, true, query+"z", true).entrySet());
    }        
}

4

2 に答える 2

3

この場合、それらを volatile と宣言したり、何らかの種類の同期で保護したりする必要はありません。構築スレッドがそれらを構築し、メインメモリと同期する限り。

そのためには、構築スレッドが volatile 変数に 1 回書き込むか、同期ロックを開始/終了するだけで済みます。これにより、メモリ バリアが通過し、すべてのローカル スレッド データがメイン スレッドになります。その後、他のすべてのスレッドがこのデータを安全に読み取ることができます。

さらに - 不必要な volatile ブロックまたは同期ブロック - 重大なパフォーマンス ペナルティが発生します - 変数へのアクセスのたびにメモリ バリアを通過します - これはコストのかかる操作です

于 2012-04-12T00:00:06.143 に答える
3

オブジェクトの構築後に可視性の問題が発生する可能性があります。つまり、コンストラクター呼び出しの直後に、マップを生成したスレッドにマップが生成されたように見える場合がありますが、少なくともすぐには、必ずしも他のスレッドにマップが生成されるとは限りません。このタイプの問題は、 Java Concurrency in Practiceの第 3 章で詳しく説明されています。ただし、マップをvolatile次のように宣言すると、次のようになります。

private static volatile TIntObjectHashMap<String> idsToNamesMap;
private static volatile TreeMap<String, Integer> namesToIdsMap;

あなたは大丈夫なはずです。

アップデート

あなたのコードをもう一度見ていて、あることに気づきました。マップはstatic- コンストラクターによってインスタンス コンテキストに入力されるのはなぜですか? まず、読者を混乱させます。第 2 に、オブジェクトの複数のインスタンスが作成された場合、他のスレッドがマップを読み取っている間に、1 つだけでなく追加の書き込みがマップに行われる可能性があります。

それらを非にするか、静的初期化ブロックstaticに入力する必要があります。

于 2012-04-11T23:53:57.230 に答える