2

マルチスレッドプログラムで ConcurrentHashMap を使用しています。マップは、サーバーに関する詳細情報 (オンラインかどうか、最近の使用量など) を含むオブジェクトに ServerID をマップします。ServerID と ServerInformation はどちらも不変です。

サーバー情報を更新するために、この質問でポイント B) として提案されていることを多かれ少なかれ行っています: ConcurrentHashMap の値を変更するための推奨される方法は何ですか?

すなわち(私自身の変数名を使用するように変更されています)これ:

public void addUsage(ServerID id, long moreUsage) {
    ServerInfo oldInfo = serverMap.get(id);
    ServerInfo newInfo = oldInfo.addUsage(moreUsage);
    serverMap.put(id, newInfo);
}

ここで私の質問は次のとおりです。更新が失われる可能性を排除するために、このメソッドを同期するべきではありませんか?

または、それを達成する別の方法はありますか?おそらく次のようなものです(明らかな間違いを取り除くために元のバージョンから編集されています):

public void addUsage(ServerID id, long moreUsage) {
    ServerInfo oldInfo = serverMap.get(id);
    ServerInfo newInfo = oldInfo.addUsage(moreUsage);
    while (!serverMap.replace(id, oldInfo, newInfo) ) {
        oldInfo = serverMap.get(id);
        newInfo = oldInfo.addUsage(moreUsage);
        // try again later
        Thread.sleep(SOME_TIME);
    };
}
4

1 に答える 1

2

はい、replace メソッドはこの問題を解決する正しい方法です。値オブジェクトの equals を適切にオーバーライドすることを忘れないでください!

(これは、 newValue の計算が比較的安価で、衝突が比較的まれであることを前提としています。集中的な計算であり、衝突が一般的である場合は、ミューテックスを導入して計算をシリアル化する価値があるかもしれません。)

実際にワーカー スレッドをスリープ状態にするよりも、ジョブをスレッドに供給しているキューに再送信するか、遅延キューに入れる方がおそらく良いでしょう。スリープ状態のワーカー スレッドは、全体的に悲しく、スケーラビリティに欠けています。

于 2013-11-08T21:45:27.227 に答える