更新/追加のソースを変更して重複を避けることができない場合は、どこかにチョーク ポイントを作成する必要があります。目標は、可能な限り競合を最小限に抑えることです。
これを行う 1 つの方法は、要求キュー、作業キュー、およびルックアップ用の ConcurrentHashMap を用意することです。すべての新しいリクエストは、単一の「ゲートキーパー」スレッドによって処理されるリクエスト キューに追加されます。ゲートキーパーは、一度に 1 つの要求を取得するか、キューを空にして保留中のすべての要求をループで処理し、その側での競合を減らすことができます。
リクエストを処理するために、ゲートキーパーは ConcurrentHashMap で putIfAbsent を実行します。戻り値が null の場合、更新/挿入要求を実際の作業キューに追加できます。値がすでにマップにある場合は....以下の #2 を参照してください。putIfAbsent はアトミックであるため、現実的には複数のゲートキーパーを使用できますが、HashMap での競合が増えるだけです。ゲートキーパーの実際の処理時間は非常に短いため、リクエスト キューにそれらを追加しても、実際には何も得られません。
ワーク キュー スレッドは、同じレコードを変更しない限り、複数の更新/挿入を同時に処理できます。ワーク キュー スレッドが要求の処理を終了すると、ConcurrentHashMap から値を削除して、ゲートキーパーがそのレコードを再度変更しても安全であることを認識できるようにします。
--
考慮すべき点:
1) 同時にできることをどのように定義しますか? 2 つの異なるリクエストが同じドキュメントを同時に変更することは望ましくないため、リクエスト全体をハッシュするべきではないでしょう。
2) すでにキューに重複があるために現在処理できないリクエスト (またはポイント 1 のように同じドキュメントを変更するリクエスト) はどうしますか? それらを捨てる?それらを定期的に再試行する二次更新キューに入れますか? 元のリクエスタのリクエストが無期限保留パターンの場合、どのように対応しますか?
3) リクエストが処理される順序は重要ですか?