Ok Boom

” 勿忘初心,方得始终 “

Java 并发包揭秘之 AtomicBoolean

1
2
3
4
5
6
7
8
9
10
11
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;

我们可以看到在 AtomicBoolean 在类加载的时候,通过 unsafe 的 objectFieldOffset 方法来获取 valueOffset 相对于 AtomicBoolean 实例对象的其实位置偏移量

那么 AtomicBoolean 是如何在多线程中保证 value 的可见性和原子性呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;
int u = update ? 1 : 0;
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}

我们可以看到 compareAndSwapInt 其实就是 CAS(比较与交换,Compare and swap)无锁算法
当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试

compareAndSet 方法有 2 个参数,一个是期望值 (expected),一个是更新值 (update);
如果 value 的值和期望值一致,则更新值设定给 value,返回 true,表明成功;否则就不设定,并返回 false。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) {
AtomicBoolean atomicBoolean = new AtomicBoolean(false);

new Thread(new Runnable() {
@Override
public void run() {
atomicBoolean.compareAndSet(true, true);
System.out.println(atomicBoolean.get());
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
atomicBoolean.compareAndSet(false, true);
System.out.println(atomicBoolean.get());
}
}).start();
}

参考
https://en.wikipedia.org/wiki/Compare-and-swap