1

序文: ほとんどの場合、揮発性フィールドを使用しても測定可能なパフォーマンス ペナルティが発生しないことはわかっていますが、この質問はより理論的であり、非常に高い相関性をサポートする設計を対象としています。

List<Something>構築後に埋められるフィールドがあります。パフォーマンスを節約するために、リストを読み取り専用のマップに変換したいと思います。これを行うには、少なくとも volatile Map フィールドが必要になるため、すべてのスレッドで変更が表示されるようにします。

私は次のことを考えていました:

マップマップ;

public void get(オブジェクトキー){
    if(map==null){
        Map temp = new Map();
        for(オブジェクト値: super.getList()){
            temp.put(値.getKey(),値);
        }
        マップ = 温度;
    }
     戻り map.get(キー);
}

これにより、シリアライズされた方法で get ブロックに入ったとしても、複数のスレッドがマップを生成する可能性があります。スレッドがマップの異なる同一インスタンスで動作する場合、これは大きな問題にはなりません。もっと気になるのは:

1 つのスレッドが新しい一時マップをマップ フィールドに割り当て、次に 2 番目のスレッドがそれを確認してmap!=null、新しいマップ フィールドを生成せずにマップ フィールドにアクセスすることは可能ですか?まだ共有メモリ領域にプッシュされていない場所はどこですか?

コメントへの回答:

  • スレッドは一時マップのみを変更し、その後は読み取り専用になります。
  • List を Map に変換する必要があるのは、特別な JAXB セットアップが原因で、最初から Map を持つことが実現できないためです。
4

4 に答える 4

3

1 つのスレッドが新しい一時マップをマップ フィールドに割り当て、次に 2 番目のスレッドがそれを確認してmap!=null、新しいマップ フィールドを生成せずにマップ フィールドにアクセスすることは可能ですか?まだ共有メモリ領域にプッシュされていない場所はどこですか?

はい、これは絶対に可能です。たとえば、最適化コンパイラは実際にはローカルtemp変数を完全に削除し、例外が発生した場合に復元されてmapいれば、フィールドをずっと使用することができます。mapnull

map同様に、スレッドは、まだ完全に設定されていないにもかかわらず、null 以外、空でないことを確認することもできます。Mapまた、クラスが同時読み取りと書き込み (または問題を回避するために使用) を許可するように注意深く設計されていない限り、あるスレッドがそのメソッドを呼び出しているときに別のsynchronizedスレッドがそのメソッドを呼び出している場合、奇妙な動作が発生する可能性もあります。getput

于 2012-03-25T21:39:41.700 に答える
1

ctor で Map を作成し、それを final と宣言できますか? 他の人がマップを変更できるようにマップをリークしない限り、get() を複数のスレッドで安全に共有できるようにするのに十分です。

于 2012-03-25T21:17:46.037 に答える
0

他のスレッドが「半分完成した」マップを読み取ることができるかどうか本当に疑問がある場合 (私はそうは思いませんが、絶対にないとは言いません ;-)、これを試してみてください。

マップが null または完全です

static class MyMap extends HashMap {
   MyMap (List pList) {
    for(Object value : pList){
        put(value.getKey(), value);
    }
   }
}

MyMap map;

public Object get(Object key){
    if(map==null){
        map = new MyMap (super.getList());
    }
    return map.get(key);
 }

または、誰かが新たに導入された問題を認識していますか?

于 2012-03-26T12:22:33.563 に答える
0

前述の可視性の問題に加えて、元のコードには別の問題があります。ここで NullPointerException をスローできます。

return this.map.get(key)

これは直感に反しますが、正しく同期されていないコードから予想されることです。

これを防ぐためのサンプル コード:

Map temp;
if ((temp = this.map) == null)
{

    temp = new ImmutableMap(getList());
    this.map = temp;
}
return temp.get(key);
于 2016-06-06T12:23:04.967 に答える