簡體   English   中英

AtomicBoolean.set(flag) 和 AtomicBoolean.compareAndSet(,flag? flag) 有什么區別?

[英]What is the difference between AtomicBoolean.set(flag) and AtomicBoolean.compareAndSet(!flag, flag)?

我想知道調用之間是否有任何區別(或可能的副作用):

AtomicBoolean.set(true)

AtomicBoolean.compareAndset(false, true)

AtomicBoolean#set的 JavaDoc 指出:

無條件設置為給定值。

雖然AtomicBoolean#compareAndSet指出:

如果當前值 == 預期值,則以原子方式將值設置為給定的更新值。

在這兩種情況下,該值都將設置為 true。 那么區別是什么呢?

如果值已經為true compareAndset(false, true)將返回false
它實際上相當於!getAndSet(true)

那么你引用的文字明確說明了這兩個操作之間的區別。 但為了更清楚,如果忽略原子性方面,第一個相當於:

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)將狀態設置為true ,而compareAndset(false, true)將狀態設置為true如果它尚未為true 所以,是的,對AtomicBoolean狀態的凈影響是相同的。

但是,您會注意到return值根據AtomicBoolean對象的初始狀態而有所不同......因此從該角度來看,即使使用這些參數值,方法也不相同。

登陸這里從性能角度尋找答案。 由於不確定本機實現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

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 的值。

CAS算法將在高爭用情況下具有性能影響,因為compareAndSet(false, true)compareAndSet(false, true)直到成功為止。 因此,如果不需要原子性,則普通布爾值可能是更好的選擇。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM