AtomicBoolean 完全源码解析

  AtomicBoolean可以用于原子的更新boolean变量的值,但不可用于替换java.lang.Boolean。

  AtomicBoolean依赖CAS原始实现,在多线程高并发环境下,能保证只有一个线程对AtomicBoolean变量的修改有效。

  演示示例:

package com.securitit.serialize.atomics;

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanTester {
	// 初始化AtomicBoolean变量bool值为false.
	private static AtomicBoolean bool = new AtomicBoolean(false);
	
	public static void main(String[] args) {
        // 通过CAS设置bool变量值为true.
        // 即使在多线程环境下,仍然可以保持正常的程序语义.
		if(bool.compareAndSet(false, true)) {
            // 若更新成功,打印bool的值.
			System.out.println(bool.get());
		}
	}
	
}

  输出结果:

true

  源码分析:

  同样让我们分析一下AtomicBoolean类中的API。

  实现基础:

private volatile int value;

  AtomicBoolean类中有一个volatile int类型变量,AtomicBoolean的所有操作都是基于此int类型变量在0和1之间的变换实现的。具体volatile的特性以及内存实现方式,可以参照本博介绍volatile的文章。volatile能保证单一赋值操作的原子性。

​  构造方法:

public AtomicBoolean();
public AtomicBoolean(boolean initialValue);

  AtomicBoolean提供了两种构造方法,无参构造方法内无实现,初始值取决于成员变量value的初始值,由于是int类型,初始值为0,即false。一个参数构造方法,传入参数作为初始值。

  普通取值/赋值:

扫描二维码关注公众号,回复: 11363164 查看本文章
public final boolean get();
public final void set(boolean newValue);

  AtomicBoolean提供了get/set用于进行普通赋值操作,这两个操作在多线程环境下,由于不具备CAS处理功能,所以可能导致意想不到的问题。

  CAS取值/赋值:

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

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

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

  以上三个方法都是依赖CAS来实现的,差别在于:

​  · getAndSet:只允许传入新值,通过上面源码可以看出,此方法在get和set之间是不允许其它线程对其进行操作的,若set失败,会重新尝试。

  · compareAndSet:指定期望值和新值,进行CAS比较替换操作。

​  · weakCompareAndSet:weakCompareAndSet的内部实现和compareAndSet一样,唯一区别在于方法本身compareAndSet由final修饰,而weakCompareAndSet没有。

  官方文档注释:以原子的方式更新这个更新器所管理的对象(obj)的成员变量,并且将这个成员变量更新为给定的更新后的值(update)如果当前值等于期望值(expect)时,当存在其他使用compareAndSet或者set的情况下,这个方法可以确保是原子的,但如果你用其他的方式去改变这个成员变量时(如,使用直接赋值的方式 field=newField),那么它是不会遵循这个原子性的。该方法可能可能虚假的失败并且不会提供一个排序的保证,所以它在极少的情况下用于代替compareAndSet方法。

  个人来看,weakCompareAndSet和compareAndSet至少在JDK1.8版本及之前,没有明显差别,两个方法的唯一差别只是weakCompareAndSet没有final修饰,所以不同厂商的虚拟机可以对其进行改造,根据自身指令级确定CAS实现,也就是不确定性的由来。

  惰性赋值

public final void lazySet(boolean newValue);

  AtomicBoolean操作都是依赖volatile int变量来实现,volatile关键字保证了int类型变量在多个线程中的可见性,lazySet的作用就是抵消这种保证,让volatile int变量可以如普通变量一样操作,在多线程环境中,恢复可见性问题。

  注:文中源码均来自于JDK1.8版本,不同版本间可能存在差异。

  如果有哪里有不明白或不清楚的内容,欢迎留言哦!

猜你喜欢

转载自blog.csdn.net/securitit/article/details/106753425
今日推荐