[英]Difference between getAndSet and compareAndSet in AtomicBoolean
[英]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.