この問題を解決する簡単な方法は、実行中の処理スレッドの数に等しい配列内のサブキューを維持することです。 1つのマスタースレッドが単一のメインキューから項目を取り出し、オブジェクトキーのhashCode(タスクを識別し関連付けるhashCode)のモジュロを介してインデックスされたサブキューにサブスレッドを追加します。
など。
int queueIndex = myEntity.getKey().hashCode() % queues.length;
1つのスレッドだけがそのキューを処理し、同じエンティティのすべてのタスクがそのキューに送信されるため、競合状態は発生しません。
この解決策は、一部のスレッドが他のスレッドより大きなキューになる可能性があるため、不完全です。実際には、これは問題になることはまずありませんが、考慮する必要があります。簡単な解決策と
問題:(Aurandが指摘したように)単一のキューのオフのアイテムを引っ張った後、影響を受けたエンティティのための明確な何かにロックの
単純ソリューションは、競合状態を持っています。与えられた:
task1
と
task2
の両方が同じエンティティ
entity1
を編集し、キュー上で動作
thread1
と
thread2
がある
Master Queue [ Task1(entity1), Task2(entity1), ... ]
、その後、イベントの予想/所望の配列は次のとおりです。
- スレッド1は、タスク1を取りますentity1上
- スレッド1ロック
- スレッド1がentity1
- のThを編集READ1がentity1
- のロックを解除するスレッド2は
- スレッド2がentity1
- スレッド2はロックが、それは、スレッドのrunメソッドの最初のステートメントである場合でも、entity1
残念ながら
のロックを解除を編集entity1タスク2
スレッド2ロックを取ります
- スレッド1がタスク1をとります。
- スレッド2が
- スレッド2が編集entity1タスク2
- スレッド2ロックを取るentity1
- スレッド2が
- スレッド1が編集entity1 entity1
- スレッド1のロックロックを解除entity1
- スレッド1は
entity1
はこれを避けるためにロックを解除します、各スレッドはキューからタスクを取得する前に何か(例えばキュー)をロックする必要があります。親ロックを保持したままエンティティのロックを取得します。しかし、この親ロックを保持してエンティティロックを取得するのを待っている間は、すべてをブロックしたくないので、エンティティロックを試してから、取得に失敗した場合(おそらく別のキューに入れる) 。全体的に状況は軽微ではありません。
擬似コードを入れて分かりやすくする方がいいでしょう。しかし、それは可能性ですか?:1人のエグゼキュータのように、複数のエグゼキュータを使用することは可能ですか? 'JoeのアップデートをJoeのためにアップデートすると安全です.' –
実行可能ファイル内の名前を同期させても、順次実行が保証されないことに注意してください。エグゼキュータは、(エグゼキュータがシングルスレッドでない限り)サブミット順にタスクが実行されることを約束しません。 – Aurand
@Jose Renato:名前ごとに1つのスレッドを使用します。以下の答えを参照してください。各スレッドは順序の整合性を保証します。 –