外部システムにリクエストを送信するときに、厳密なラウンド ロビン スケジューリングを実装したいと考えています。2 つの外部システム サーバーがあります。最初のリクエストは「System1」に送信され、2 番目のリクエストは「System2」に送信され、次のリクエストは「System1」に送信される必要があります。
リクエストを送信するサーバーが 2 つしかないため、ブロッキングやコンテキスト スイッチを使用せずに最大のパフォーマンスが必要なため、CAS 操作を利用するため、AtomicBoolean を選択しました。
私の実装クラス
1. RoundRobinTest.java
package com.concurrency;
import java.util.Iterator;
public class RoundRobinTest
{
public static void main(String[] args)
{
for (int i = 0; i < 500; i++)
{
new Thread(new RoundRobinLogic()).start();
}
try
{
// Giving a few seconds for the threads to complete
Thread.currentThread().sleep(2000);
Iterator<String> output = RoundRobinLogic.output.iterator();
int i=0;
while (output.hasNext())
{
System.out.println(i+++":"+output.next());
// Sleeping after each out.print
Thread.currentThread().sleep(20);
}
}
catch (Exception ex)
{
// do nothing
}
}
}
2.RoundRobinLogic.java (静的 AtomicBoolean オブジェクトを持つクラス)
package com.concurrency;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicBoolean;
public class RoundRobinLogic implements Runnable
{
private static AtomicBoolean bool = new AtomicBoolean(true);
public static Queue<String> output = new ConcurrentLinkedDeque<>();
@Override
public void run()
{
if(bool.getAndSet(false))
{
// Sending the request to first system
output.add("Request to System1");
}
else if(!bool.getAndSet(true))
{
// Sending the request to first system
output.add("Request to System2");
}
}
}
出力:
......................
314:Request to System1
315:Request to System2
316:Request to System1
317:Request to System2
318:Request to System1
319:Request to System1
320:Request to System2
321:Request to System2
322:Request to System1
323:Request to System2
324:Request to System1
325:Request to System2
......................
リクエスト 318 と 319 は同じサーバーに送信されており、このシナリオでは AtomicBoolean が失敗します。私のアプリケーションでは、一度に 1000 ~ 2000 のスレッドが共有オブジェクトにアクセスしている可能性があります。実際のJava並行性から、私は以下を見てきました。
競合レベルが高い場合、ロックはアトミック変数よりもパフォーマンスが優れている傾向がありますが、より現実的な競合レベルでは、アトミック変数がロックよりもパフォーマンスが優れています。これは、ロックが競合に反応してスレッドを一時停止し、共有メモリ バス上の CPU 使用率と同期トラフィックを削減するためです。 低から中程度の競合で、アトミックはより優れたスケーラビリティを提供します。競合が多い場合、ロックはより優れた競合回避を提供します。(単一 CPU システムでは、CAS ベースのアルゴリズムはロック ベースのアルゴリズムよりもパフォーマンスが優れています。これは、読み取り変更書き込み操作の途中でスレッドが横取りされるというまれなケースを除いて、CAS は常に単一 CPU システムで成功するためです。)
今、私は以下の質問があります。
- ラウンドロビン要求の送信を実現するために、他の効率的なノンブロッキングの方法はありますか。
- 競合が激しい場合、AtomicBoolean が失敗する可能性はありますか? 私が理解しているのは、競合が激しいためにパフォーマンス/スループットが低下する可能性があるということです。しかし、上記の例では AtomicBoolean は失敗します。なんで ?