大于比较和交换

时间:2012-02-20 15:15:02

标签: java multithreading synchronization nonblocking

正如标题所暗示的那样,我正在寻找一种比较和交换的实现方式,但是要比较大:

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,因此我需要循环并重试。

此实现是否正确(线程安全)?

4 个答案:

答案 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;
 }