私は、純粋な好奇心から、実際のソースを研究するために実際に時間をかけました。その背後にあるアイデアは非常に単純です。この記事を書いている時点での最新バージョンは 3.2.1 です。
コンシューマーが読み取るデータを保持する、事前に割り当てられたイベントを格納するバッファーがあります。
バッファは、バッファ スロットの可用性を示す長さのフラグの配列 (整数配列) によってサポートされます (詳細については、さらに参照してください)。配列は java#AtomicIntegerArray のようにアクセスされるため、この説明では配列が 1 であると想定することもできます。
プロデューサーの数に制限はありません。プロデューサがバッファに書き込もうとすると、長い数値が生成されます (AtomicLong#getAndIncrement を呼び出す場合と同様に、Disruptor は実際には独自の実装を使用しますが、同じように機能します)。これを生成された long を ProducerCallId と呼びましょう。同様に、consumerCallId は、コンシューマがバッファからスロットを読み取る ENDS 時に生成されます。最新の consumerCallId がアクセスされます。
(コンシューマーが多い場合は、ID が最も小さい呼び出しが選択されます。)
次に、これらの ID が比較され、両者の差がバッファー側よりも小さい場合、プロデューサーは書き込みを許可されます。
(producerCallId が最近の consumerCallId + bufferSize よりも大きい場合は、バッファーがいっぱいであることを意味し、プロデューサーはスポットが利用可能になるまでバス待機を強いられます。)
その後、生産者は自身の callId (prducerCallId modulo bufferSize) に基づいてバッファー内のスロットを割り当てられますが、bufferSize は常に 2 のべき乗 (バッファーの作成時に適用される制限) であるため、使用される実際の操作は producerCallId & (bufferSize - 1 )))。その後、そのスロットのイベントを自由に変更できます。
(実際のアルゴリズムはもう少し複雑で、最適化のために最近の consumerId を別のアトミック参照にキャッシュする必要があります。)
イベントが変更されると、変更が「公開」されます。フラグ配列のそれぞれのスロットを公開すると、更新されたフラグが入ります。フラグの値は、ループの数です (producerCallId を bufferSize で割った値です (ここでも bufferSize は 2 の累乗であるため、実際の操作は右シフトです)。
同様に、任意の数のコンシューマが存在する可能性があります。コンシューマーがバッファーにアクセスするたびに、consumerCallId が生成されます (コンシューマーがディスラプターにどのように追加されたかに応じて、ID 生成で使用されるアトミックが共有されるか、それぞれで個別に使用される場合があります)。次に、この consumerCallId が最新の ProducentCallId と比較され、2 つのうち小さい場合、リーダーは処理を続行できます。
(同様に、producerCallId が consumerCallId に対して偶数である場合、それはバッファーが空であり、コンシューマーが強制的に待機することを意味します。待機の方法は、ディスラプターの作成中に WaitStrategy によって定義されます。)
個々のコンシューマー (独自の ID ジェネレーターを持つコンシューマー) の場合、次にチェックされるのは、バッチで消費する機能です。バッファー内のスロットは、consumerCallId (インデックスはプロデューサーと同じ方法で決定されます) に対応するスロットから、最近の ProducerCallId に対応するスロットの順に調べられます。
これらは、フラグ配列に書き込まれたフラグ値と、consumerCallId 用に生成されたフラグ値を比較することにより、ループで検査されます。フラグが一致する場合は、スロットを埋めているプロデューサーが変更をコミットしたことを意味します。そうでない場合、ループは中断され、コミットされた最大の changeId が返されます。ConsumerCallId から changeId で受信されるまでのスロットは、バッチで消費できます。
コンシューマーのグループ (ID ジェネレーターが共有されているもの) が一緒に読み取られる場合、それぞれが 1 つの callId のみを取得し、その 1 つの callId のスロットのみがチェックされて返されます。