当我向外部系统发送请求时,我想实施严格的循环调度。有两个外部系统服务器。第一个请求应该发送到“System1”,第二个请求必须发送到“System2”,下一个请求必须发送到“System1”,依此类推。
由于我只有两台服务器可以向其发送请求,并且由于我希望在没有任何阻塞和上下文切换的情况下获得最大性能,因此我选择了 AtomicBoolean,因为它使用了 CAS 操作。
我的实现类
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 使用率和共享内存总线上的同步流量。 低到中等的争用,原子提供更好的可扩展性;对于高争用,锁提供更好的争用避免。(基于 CAS 的算法在单 CPU 系统上也优于基于锁的算法,因为 CAS 总是在单 CPU 系统上成功,除非在读取修改写入操作中间线程被抢占的不太可能的情况。)
现在我有以下问题。
- 有没有其他高效的非阻塞方式,来实现轮询请求发送。
- 在激烈的争论下,AtomicBoolean 是否有可能失败?我的理解是,性能/吞吐量可能会由于激烈的争用而下降。但是在上面的例子中 AtomicBoolean 失败了。为什么 ?