2
    private static Map<Integer, String> map = null;

    public static String getString(int parameter){

        if(map == null){

            map = new HashMap<Integer, String>();
            //map gets filled here...

        }

        return map.get(parameter);
    }

マルチスレッドが進むにつれて、そのコードは安全ではありませんか?

4

7 に答える 7

4

前述のように、それは間違いなく安全ではありません。マップの内容が getString() のパラメーターに基づいていない場合は、次のように静的イニシャライザーとしてマップを初期化することで、より適切なサービスを提供できます。

private static final Map<Integer, String> MAP = new HashMap<Integer,String>();

static {
  // Populate map here
}

上記のコードは、クラスがロードされるときに 1 回呼び出されます。これは完全にスレッド セーフです (ただし、マップへの将来の変更はそうではありません)。パフォーマンス上の理由から遅延ロードしようとしていますか? もしそうなら、これははるかに安全です:

private static Map<Integer, String> map = null;

public synchronized static String getString(int parameter){

    if(map == null){

        map = new HashMap<Integer, String>();
        //map gets filled here...

    }

    return map.get(parameter);
}

synchronizedキーワードを使用すると、一度に 1 つのスレッドだけがメソッドを実行できるようになり、マップ参照への変更が常に伝達されるようになります。

この質問をしている場合は、「Java Concurrency in Practice」を読むことをお勧めします。

于 2013-03-05T21:45:25.627 に答える
2

競合状態?おそらく。

の場合、2つのスレッドmapが同時にnullチェックすると、それぞれが個別のマップを割り当てます。これは、主に不変であるif (map == null)かどうかに応じて、問題になる場合と問題にならない場合があります。mapマップが不変であっても、マップにデータを入力するコストも問題になる可能性があります。

メモリーリーク?いいえ。

ガベージコレクターは、競合状態に関係なく正しく機能します。

于 2013-03-05T21:24:18.710 に答える
1

mapマルチスレッドのシナリオでは、初期化を 2 回行うリスクがあります。

マネージ言語では、ガベージ コレクターは、参照されなくなったインスタンスを最終的に破棄します。アンマネージ言語では、上書きされたマップに割り当てられたメモリを解放することはありません。

いずれにしても、複数のスレッドが初期化コードを同時に実行しないように、初期化を適切に保護する必要があります。

1 つの理由: 最初のスレッドが HashMap の初期化の途中である可能性があります。一方、2 番目のスレッドは長くなり、それmapが null ではないことを確認し、部分的に初期化されたデータ構造を陽気に使用しようとします。

于 2013-03-05T21:22:06.687 に答える
1

競合状態のため、マルチスレッドの場合は安全ではありません。

しかし、マップの遅延初期化が本当に必要ですか? とにかくマップが使用される場合は、熱心な初期化を行うことができるようです..

于 2013-03-05T21:36:35.937 に答える
1

他の人が述べたように、上記のコードはスレッドセーフではありません。マップは2回初期化できます。同期を追加して上記のコードを修正しようとするかもしれません。これは「ダブル チェック ロック」として知られています。このアプローチの問題点と潜在的な修正方法について説明している記事を次に示します。

最も簡単な解決策は、フィールドを別のクラスの静的フィールドにすることです。

class HelperSingleton {
  static Helper singleton = new Helper();
 }

Bill Pugh の記事で説明されているように、volatile キーワードを使用して修正することもできます。

于 2013-03-05T21:41:50.443 に答える
0

Java 6 を使用している場合は、ConcurrentHashMap を使用します

ConcurrentHashMap JavaDoc

于 2013-03-05T22:21:50.897 に答える
0

いいえ、このコードは複数のスレッドで安全に使用できません。

マップの初期化に競合状態があります。たとえば、複数のスレッドが同時にマップを初期化し、互いの書き込みを上書きする可能性があります。

スレッドによって行われた変更が他のスレッドから見えるようにするためのメモリ バリアはありません。たとえば、各スレッドは別のスレッドによって書き込まれた値を「見る」ことがないため、マップの独自のコピーを使用できます。

マップが同時にアクセスされるときに不変条件が保持されることを保証する原子性はありません。たとえばget()、同時操作中に別のスレッドがバケットを再ハッシュしたため、操作を実行しているスレッドが無限ループに陥る可能性がありますput()

于 2013-03-05T21:47:48.940 に答える