2016-04-14 13 views
0

サーバーの起動時に初期化される静的なHashMapがあります。クライアントはログイン時にこのマップからデータを初期化します。
このマップを更新する必要がありますが、クライアントはこのマップから同時にログインしてデータを取得できます。クライアントが読み込み中にHashMapをリフレッシュする方法

マップの参照を以下のように変更することはできますか? 私は​​を使用できません。同時に読み取ることができ、1つのスレッドしか書いていないからです。

public void refresh() { 
    synchronized (MyClass.class) { 
     Map<String, Object> newMap = prepareData(); 
     map = Collections.unmodifiableMap(newMap); 
    } 
} 

そして、あなたのマップを:すべてのマップの

public void refresh() { 
     Map<String, Object> newMap = prepareData(); 
     map = newMap; 
    } 
+0

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html –

+0

可能な重複http:// stackoverflow。com/questions/28147889/how-to-lock-a-hashmap-refresh中 – nyname00

答えて

1

は、「リフレッシュ」ことを前提としていますあなたは(たとえば)ファイルからロードされた新鮮なセットでハッシュマップ内のすべてのエントリを置き換えることを意味します。

新しいマッピングのキーのセットが元のマッピングのキーのスーパーセットである場合、そしてアプリケーションが古いマッピングの一部と新しいマッピングの一部を同じに設定できるかどうかを気にしない場合HashMapの代わりにConcurrentHashMapを使用し、そのエントリをputコールのシーケンスに置き換えることができます。

しかし、キーが異なる(または異なる可能性がある)場合、または更新がクライアントの観点からアトミックである必要がある場合、ConcurrentHashMapは機能しません。代わりにmapvolatileと宣言し、質問ごとにrefresh()メソッドを実装する必要があります。

指摘したように、​​(またはシングルライター/マルチリーダーロック)を使用すると、並行性のボトルネックが発生する可能性があります。


注:volatileを使用しても、後者は実行可能なソリューションである場合にConcurrentHashMapを使用するよりも優れたパフォーマンスを提供する可能性があります。

+0

LinkedHashMapを使用する必要がある場合、誰もが同じ順序で読み込み可能なので、揮発性のLinkedHashMapが私の問題を正しく解決しますか? – noname

+0

はい、そうです。 'volatile 'を使うと、スレッドセーフなアトミックな操作としてマップを置き換えることができます。これは標準的な 'Map'型で動作します。 –

1

まず、各スレッドは、それの最後のバージョンを持っていることを確実にするためにvolatileとして宣言する必要があり、その後、ここで先に進むことができるかであります以下のように宣言されます:

private static volatile Map<String, Object> map = ... 
+0

私はクライアントのために同期文を書く必要はありませんか?これらは、この場合 – noname

+0

のように並行して読み取ることができます。マップはスレッドセーフである必要があります。そのため、Collections.unmodifiableMapのおかげで、変更不可能なオブジェクトはスレッドセーフです。 –

+0

これにより、あなたが書いている間に読書を止めるために、あなたは同じ錠の読書アクセスを同期させる必要があります。あなたもクライアントを同期させる必要があります。そして、あなたはマップ自体をロックするべきであり、いくつかのランダムな 'myclass'オブジェクトでロックするべきではありません。また、マップをクリアして新しいオブジェクトに置き換えるのではなく、クライアントが変更されたことを決して知ることはできません。 –

1

クライアントが古いデータを持っている場合は、新しいマップを作成して静的参照をポイントするだけです。あなたがこれをやっている間に新しいクライアントが来たら、古いデータが得られ、害はありません。新しい値への切り替え(再割り当て)が発生した後に新しいクライアントが現れたら、新しい値が得られます。ジョブが完了しました。

あなたが変更されていない場合は、おそらく、変更前の他のクライアントにも通知しなければなりません。この場合、更新にオブザーバーパターンを使用します。このパターンでは、更新が完了した後、できるだけ早く更新されるため、クライアントが更新中に接続すると問題ありません。

BTW:すべての場合、本当に何かに「静的」を使用すべきではありません。それだけで問題を引き起こします。むしろ、マップを保持している非スタティックなシングルトンを作成し、それをクライアント/サービス/その他に挿入します。

関連する問題