我想知道调用之间是否有任何区别(或可能的副作用):
AtomicBoolean.set(true)
和
AtomicBoolean.compareAndset(false, true)
状态的 JavaDoc AtomicBoolean#set
:
无条件设置为给定值。
虽然AtomicBoolean#compareAndSet
说:
如果当前值 == 预期值,则自动将值设置为给定的更新值。
在这两种情况下,该值都将设置为 true。那么区别是什么呢?
我想知道调用之间是否有任何区别(或可能的副作用):
AtomicBoolean.set(true)
和
AtomicBoolean.compareAndset(false, true)
状态的 JavaDoc AtomicBoolean#set
:
无条件设置为给定值。
虽然AtomicBoolean#compareAndSet
说:
如果当前值 == 预期值,则自动将值设置为给定的更新值。
在这两种情况下,该值都将设置为 true。那么区别是什么呢?
compareAndset(false, true)
false
如果值已经是将返回true
。
它实际上相当于!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)
将 state 设置为true
,并将compareAndset(false, true)
state 设置为true
if it is not already 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)
它会被淘汰,直到它成功。因此,如果不需要原子性,则纯布尔值可能是更好的选择。