优秀的编程知识分享平台

网站首页 > 技术文章 正文

AtomicBoolean操作详解及原理分析

nanyue 2024-08-25 10:38:09 技术文章 6 ℃

介绍

AtomicBoolean 是使用CAS实现的对布尔值进行原子更新的类。

什么是CompareAndSwap(CAS? 即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。CAS是一条CPU的原子指令(cmpxchg指令),不会造成所谓的数据不一致问题,AtomicBoolean 调用 Unsafe 类提供的CAS方法(如compareAndSwapXXX)实现了原子操作。要了解 Unsafe 的基本运用,请查看 《Unsafe的基本操作》

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

private volatile int value;

查看源码可知:AtomicBoolean 类在实例化时会首先获取 value 的偏移量(valueOffset),后续方法中 Unsafe 类都会根据 valueOffset 进行数据操作。

并且 value 需要声明为 volatile ,以保证并发时线程间的可见性。

基本操作

以下以JDK 8中的源码进行示例。

1、创建 AtomicBoolean 实例

AtomicBoolean 提供了两个构造方法可供使用,如下:

public AtomicBoolean(boolean initialValue) {
    value = initialValue ? 1 : 0;
}

public AtomicBoolean() {
}

因此实例化 AtomicBoolean 时按需调用对应的构造函数即可。

2、获取值

可以使用 get() 方法:

AtomicBoolean atomicBoolean = new AtomicBoolean();
boolean value = atomicBoolean.get();
System.out.println(value); // 输出:false

3、使用 compareAndSet 进行原子更新

compareAndSet 源码如下:

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);
}

可知,该方法只会调用一次 CAS 方法进行原子更新,若失败,则返回false,否则,返回 true;但是不会进行失败重试

原子更新还有一个 weakCompareAndSet 方法:

public boolean weakCompareAndSet(boolean expect, boolean update) {
    int e = expect ? 1 : 0;
    int u = update ? 1 : 0;
    return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}

由于其实现与 compareAndSet 一致,因此,该方法调用结果也与 compareAndSet 一致。

4、设置值

可以使用 set() 方法对值进行重新设置,能保证线程可见性,非常简单。

atomicBoolean.set(true);

也可以使用 lazySet() 进行值设置:

public final void lazySet(boolean newValue) {
    int v = newValue ? 1 : 0;
    unsafe.putOrderedInt(this, valueOffset, v);
}

底层实现为 unsafe.putOrderedInt ,不保证线程可见性。

5、核心操作 getAndSet

以原子方式设置为给定值并返回前一个值,底层实现如下:

public final boolean getAndSet(boolean newValue) {
    boolean prev;
    do {
        prev = get();
    } while (!compareAndSet(prev, newValue));
    return prev;
}

可知,底层使用循环不断重试调用 compareAndSet ,直到 compareAndSet 返回 true(即设置成功)为止。

总结:在开发过程中,涉及到的核心方法是 getAndSet ,可保证并发情况下的数据一致性。

最近发表
标签列表