AtomicBoolean.set(flag)和AtomicBoolean.compareAndSet(!flag,flag)有什么区别?

时间:2012-11-13 15:38:55

标签: java java.util.concurrent compare-and-swap

我想知道调用之间是否存在任何差异(或可能的副作用):

AtomicBoolean.set(true)

AtomicBoolean.compareAndset(false, true)

AtomicBoolean#set的JavaDoc声明:

  

无条件地设置为给定值。

虽然AtomicBoolean#compareAndSet说明:

  

如果当前值==期望值,则以原子方式将值设置为给定的更新值。

在这两种情况下,该值都将设置为true。那有什么区别?

4 个答案:

答案 0 :(得分:9)

如果值已经为compareAndset(false, true),则

false将返回true 它实际上相当于!getAndSet(true)

答案 1 :(得分:6)

你引用的文字明确说明了这两个操作之间的区别。但为了更清楚,如果忽略原子性方面,第一个相当于:

public void set(boolean newValue) {
    this.value = newValue;
}

,第二个相当于:

public boolean compareAndSet(boolean expected, boolean newValue) {
    if (this.value == expected) {
        this.value = newValue;
        return true;
    } else {
        return false;
    }
}

对于您的示例,set(true)将状态设置为truecompareAndset(false, true)将状态设置为true,如果它还不是true。所以,是的,对AtomicBoolean状态的净影响是相同的。

但是,您会注意到return值根据AtomicBoolean对象的初始状态而有所不同......所以从这个角度来看,即使使用这些参数值,这些方法也不相同。 / p>

答案 2 :(得分:0)

CAS算法将在高争用情况下具有性能影响,因为compareAndSet(false, true)将被取消,直到成功为止。因此,如果不需要原子性,则普通布尔值可能是更好的选择。

答案 3 :(得分:0)

登陆这里从性能角度寻找答案。由于不确定本机实现v决策块,我最终编写代码来评估相同的。根据结果​​,set()绝对是性能的优势,因为它不会经历多个决策块。请在下面找到代码和输出。

public static void main(String[] args) {
    boolean curValue = true;
    boolean dummyValue = true;
    int attempts = Integer.MAX_VALUE;


    AtomicBoolean test = new AtomicBoolean(curValue);
    long start = System.currentTimeMillis();
    for(int i=0; i<attempts; i++){
        test.set(true);
        dummyValue = !dummyValue;
    }
    System.out.println("time taken for set: "+(System.currentTimeMillis()-start));

    start = System.currentTimeMillis();
    for(int i=0; i<attempts; i++){
        test.compareAndSet(curValue, curValue); // always set the same value
        dummyValue = !dummyValue;
    }
    System.out.println("time taken for compareAndSet - same value case: "+(System.currentTimeMillis()-start));

    curValue = !curValue;
    start = System.currentTimeMillis();
    for(int i=0; i<attempts; i++){
        test.compareAndSet(curValue, !curValue); // always invert
        curValue = !curValue;
    }
    System.out.println("time taken for compareAndSet - inversion case: "+(System.currentTimeMillis()-start));
}

输出:

time taken for set: 2689
time taken for compareAndSet - same value case: 15559
time taken for compareAndSet - inversion case: 14802