Alb*_*bin 5 java algorithm multithreading atomicity atomicboolean
我想在向外部系统发送请求时实施严格的循环调度.有两个外部系统服务器.第一个请求应该转到'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
}
}
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
......................
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
......................
Run Code Online (Sandbox Code Playgroud)
请求318和319已发送到同一服务器,AtomicBoolean在此方案中失败.对于我的应用程序,1000-2000个线程可能一次访问共享对象.从实践中的Java并发性,我已经看到了以下内容.
在高争用级别,锁定往往优于原子变量,但在更现实的争用级别,原子变量优于锁定.这是因为锁通过挂起线程来对争用作出反应,从而减少共享内存总线上的CPU使用率和同步流量. 由于低到中等的争用,原子提供了更好的可扩展性; 在高争用的情况下,锁可以提供更好的争用避免.(基于CAS的算法在单CPU系统上也优于基于锁定的算法,因为CAS总是在单个CPU系统上成功,除非在读取修改写入操作的中间线程被抢占的情况不太可能.)
现在我有以下问题.
除了约翰的回答,一个更清洁,也许稍微更有效的实现RoundRobinLogic将使用AtomicInteger或AtomicLong.这消除了将当前值AtomicBoolean与新值进行比较的需要:
class RoundRobinLogic implements Runnable
{
private static final AtomicInteger systemIndex = new AtomicInteger(1);
public static final Queue<String> output = new ConcurrentLinkedDeque<>();
@Override
public void run()
{
if (systemIndex.incrementAndGet() % 2 == 0) {
// Sending the request to first system
output.add("Request to System1");
} else {
// Sending the request to second system
output.add("Request to System2");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将允许您相当容易地将其扩展到其他系统:
class RemoteSystem
{
private final String name;
RemoteSystem(String name)
{
this.name = name;
}
public String name()
{
return name;
}
}
class RoundRobinLogic implements Runnable
{
private static final AtomicInteger systemIndex = new AtomicInteger(1);
private static final RemoteSystem[] systems = new RemoteSystem[] {
new RemoteSystem("System1"),
new RemoteSystem("System2"),
new RemoteSystem("System3"),
new RemoteSystem("System4"),
};
public static final Queue<String> output = new ConcurrentLinkedDeque<>();
@Override
public void run()
{
RemoteSystem system = systems[systemIndex.incrementAndGet() % systems.length];
// Sending the request to right system
output.add("Request to " + system.name());
}
}
Run Code Online (Sandbox Code Playgroud)