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

Posted

技术标签:

【中文标题】AtomicBoolean.set(flag) 和 AtomicBoolean.compareAndSet(!flag, flag) 有啥区别?【英文标题】:What is the difference between AtomicBoolean.set(flag) and AtomicBoolean.compareAndSet(!flag, flag)?AtomicBoolean.set(flag) 和 AtomicBoolean.compareAndSet(!flag, flag) 有什么区别? 【发布时间】:2012-11-13 15:38:54 【问题描述】:

我想知道调用之间是否有任何区别(或可能的副作用):

AtomicBoolean.set(true)

AtomicBoolean.compareAndset(false, true)

AtomicBoolean#set 的 JavaDoc 声明:

无条件设置为给定值。

AtomicBoolean#compareAndSet 声明:

如果当前值 == 预期值,则自动将值设置为给定的更新值。

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

【问题讨论】:

【参考方案1】:

如果值已经是truecompareAndset(false, true) 将返回false。 它实际上相当于!getAndSet(true)

【讨论】:

没错 ;) 但我认为还有一点值得一提的是 compareAndSet 调用了原生操作 compareAndSwapInt。因此,在调用者对先前值不感兴趣的情况下,set 应该是更好的选择。感谢您的回答!【参考方案2】:

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

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 对象的初始状态而有所不同......因此从这个角度来看,即使使用这些参数值,这些方法也是不等价的。

【讨论】:

【参考方案3】:

来到这里从性能角度寻找答案。由于不确定本机实现 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

【讨论】:

【参考方案4】:

AtomicBoolean的set()和compareAndSet()方法的区别可以在线程锁机制中找到。

线程安全可以通过以下代码实现。

public class AtomicBooleanSample 
    private AtomicBoolean locked = new AtomicBoolean(false);

    private void lock() 
        while(!this.locked.compareAndSet(false, true)) 
            //a thread will be locked here
        
    

    private void unlock() 
        this.locked.set(false);
    

对于共享资源,当第一个线程执行lock()方法时,locked实例变量的值将被设置为true,因为期望值与locked的值相同并且它获取访问共享资源的锁。

在第一个线程调用unlock()方法之前,如果另一个线程尝试加锁,由于locked的值不同(true不符合预期值false)而失败,它运行在循环中,直到第一个线程将 locked 的值设置为 false。

【讨论】:

【参考方案5】:

CAS 算法 将在高争用情况下影响性能,因为 compareAndSet(false, true) 在成功之前已停用。因此,如果不需要原子性,则纯布尔值可能是更好的选择。

【讨论】:

以上是关于AtomicBoolean.set(flag) 和 AtomicBoolean.compareAndSet(!flag, flag) 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_CLEAR_TASK 行为怪异

opencv中flags&是啥意思

Android:PendingIntent的FLAG_CANCEL_CURRENT和FLAG_UPDATE_CURRENT

FLAG_ACTIVITY_CLEAR_TOP和singleTask的区别

获取记录的查询具有 some_id 和 some_flag 使得所有相同的 some_id 必须在 oracle 中具有所有 some_flag ='Y'

tensorflow代码TypeError:*:'int'和'Flag'不支持的操作数类型