正如标题所暗示的那样,我正在寻找一种比较和交换的实现方式,但是要比较大:
if(newValue > oldValue) {
oldValue = newValue;
}
其中oldValue
是某个全局共享状态,newValue
对每个线程都是私有的,不执行此操作:
synchronized(locker) {
if(newValue > oldValue) {
oldValue = newValue;
}
}
因为我想要一个非阻塞解决方案。通过研究其他非阻塞操作的源代码,我想出了这个(假设值是整数):
AtomicInteger oldValue; // shared global variable
...
public boolean GreaterThanCAS(int newValue) {
while(true) {
int local = oldValue;
if(local == oldValue) {
if(newValue > local) {
if(oldValue.compareAndSet(local, newValue) {
return true; // swap successful
} // else keep looping
} else {
return false; // swap failed
}
} // else keep looping
}
}
当// else keep looping
发生时,这意味着另一个线程在此期间更改了oldValue
,因此我需要循环并重试。
此实现是否正确(线程安全)?
答案 0 :(得分:13)
从Java 8开始,使用updateAndGet:
可以简化这一过程public boolean greaterThanCAS(int newValue) {
return oldValue.updateAndGet(x -> x < newValue ? newValue : x) == newValue;
}
请注意,如果旧值和新值相等,这也会返回true。 如果这不是所希望的行为,请尝试@Adam's answer。
答案 1 :(得分:8)
我认为您的实施没有问题,前提是没有线程会降低AtomicInteger
的值。如果他们这样做,您的代码就会对竞争条件开放。
请注意,代码可以简化如下:
public boolean GreaterThanCAS(int newValue) {
while(true) {
int local = oldValue.get();
if(newValue <= local) {
return false; // swap failed
}
if(oldValue.compareAndSet(local, newValue)) {
return true; // swap successful
}
// keep trying
}
}
答案 2 :(得分:2)
我会把它写成看起来更像:
while(true) {
int local = oldValue.get();
if(newValue > local){
if(oldValue.compareAndSwap(local, newValue) {
return true; // swap successful
} // else keep looping
}else
return false;
}
大于检查之前的等价检查是多余的。
否则它应该可以正常工作。
答案 3 :(得分:2)
@Vadzim,我会评论你的帖子,但stackoverflow说我没有足够的分数发表评论。您的答案几乎是正确的,但您的函数将始终返回false,因为getAndUpdate始终返回先前的值,或者在您的情况下返回“x”。我认为您需要做的就是将最后一个'=='替换为'&lt;',例如:
// return true if the assignment was made, false otherwise
public boolean greaterThanCAS(int newValue) {
return oldValue.getAndUpdate(x -> x < newValue ? newValue : x) < newValue;
}