3

ハッシュマップ内のさまざまなオブジェクトを持つ一種のキャッシュを処理するシングルトン クラスがあります。(キーの形式は、マップに格納されているオブジェクトのタイプに直接リンクされているため、マップは です)

マップでは、追加、取得、削除の 3 つの異なるアクションが可能です。

パブリック エントリ ポイント メソッドを使用して、マップへのアクセスを保護しました (激しいアクセスはありません)。

public synchronized Object doAction(String actionType, String key, Object data){
  Object myObj = null;
  if (actionType.equalsIgnorecase("ADD"){
    addDataToMyMap(key,data);
  } else if (actionType.equalsIgnorecase("GET"){
    myObj = getDataFromMyMap(key);
  } else if (actionType.equalsIgnorecase("REM"){  
    removeDataFromMyMap(key);      
  }
  return myObj;
}

ノート:

地図は非公開です。メソッド addDataToMyMap()、getDataFromMyMap()、removeDataFromMyMap() は非公開です。エントリ ポイント メソッドのみが public であり、クラス自体の静的な getInstance() 以外は何もありません。

map を使用する方法は他にないため、 map への同時アクセスがスレッドセーフであることを確認しますか?

マップにとって安全であれば、この原則は他の種類の共有リソースにも適用できると思います。

ご回答ありがとうございます。

デビッド

4

8 に答える 8

1

メソッドの実装を確認する必要がありますが、それで十分です。しかし、Java のコレクション API からマップを使用することをお勧めします。他のインスタンスを共有しない限り、メソッドを同期する必要はありません。

これを読んでください:http://www.java-examples.com/get-synchronized-map-java-hashmap-example

于 2012-07-13T14:21:01.753 に答える
1

はい、唯一のエントリ ポイントが doAction である限り、クラスはスレッド セーフになります。

于 2012-07-13T14:21:52.407 に答える
1

これは完全に安全です。すべてのスレッドが共通のロック (この場合はオブジェクト) を使用してアクセスしている限り、スレッドセーフです。(他の回答の方がパフォーマンスが高い場合がありますが、実装は安全です。)

于 2012-07-13T14:33:20.420 に答える
1

cacheクラスにプライベートがあり、HashMap3 つのメソッドがあり、すべてがそうpublic synchronizedでなく、他のインスタンス変数staticがない場合、キャッシュは.publicthread-safe

コードを投稿することをお勧めします。

于 2012-07-13T14:22:34.683 に答える
0

Collections.synchronizedMapを使用して、 へのアクセスを同期できますMap

于 2012-07-13T14:21:44.450 に答える
0

ConcurrentHashMapを使用する必要があります。これは、同期された doAction よりも優れたスループットを提供し、Collections.synchronizedMap() よりも優れたスレッド セーフを提供します。

于 2012-07-13T14:30:15.023 に答える
0

そのままでは、コードがスレッドセーフかどうかを判断するのは困難です。あなたの例に欠けている重要な情報は次のとおりです。

  1. メソッドは公開されていますか
  2. メソッドは同期されていますか
  3. メソッドを介してのみアクセスされるマップ

問題とその対処方法を把握するために、同期について調べることをお勧めします。ConcurrentHashMapクラスを調べると、問題に関する詳細情報が得られます。

于 2012-07-13T14:27:47.420 に答える
0

これはコードによって異なります。他の誰かが述べたように、Collections.synchronizedMap を使用できます。ただし、これはマップ上の個々のメソッド呼び出しのみを同期します。したがって、次の場合:

map.get(key);
map.put(key,value);

2 つの異なるスレッドで同時に実行され、一方は他方が終了するまでブロックされます。ただし、クリティカル セクションがマップへの 1 回の呼び出しよりも大きい場合は、次のようになります。

SomeExpensiveObject value = map.get(key);
if (value == null) {
   value = new SomeExpensiveObject();
   map.put(key,value);
}

ここで、キーが存在しないと仮定しましょう。最初のスレッドが実行され、null 値が返されます。スケジューラはそのスレッドを生成し、スレッド 2 を実行しますが、これも null 値を返します。新しいオブジェクトを構築し、マップに配置します。その後、スレッド 1 が再開し、同じことを行います。これは、まだ null 値があるためです。

これは、クリティカル セクションの周りにより大きな同期ブロックが必要な場所です。

SomeExpensiveObject value = null;

synchronized (map) {
  value = map.get(key);
  if (value == null) {
     value = new SomeExpensiveObject();
     map.put(key,value);
  }
}
于 2012-07-16T13:42:03.327 に答える