AQS源码解析-AtomicBoolean源码解析

Posted lonecloud

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AQS源码解析-AtomicBoolean源码解析相关的知识,希望对你有一定的参考价值。

  • 基本类:
  • 数组类型:
    • AtomicIntegerArray
    • AtomicLongArray
    • AtomicReferenceArray

介绍

由于在多线程条件下,如果对共享变量修改容易造成数据不一致的情况,所以对于共享变量需要保证线程安全有有如下几种方式:

  1. 使用lock或者synchronized进行同步共享变量
  2. 使用CAS方法来保证修改变量为原子性操作

该类为后者,基于CAS方式修改具有原子性。

实现原理

  1. 将boolean中的true转换成int类型表示:1表示true 0表示false
  2. 在类进行初始化的时候获取该值的内存地址
  3. 调用Unsafe.compareAndSwant方法底层通过CAS原理(CPU中cmpxchg指令)对值进行变化

技术图片

特点

  1. 基于CAS实现线程安全
  2. 实现了Cloneable接口,能被克隆
  3. 实现了Serializable接口,支持序列化传输

源码解析

成员变量

    private static final long serialVersionUID = 4654671469794556979L;
    // setup to use Unsafe.compareAndSwapInt for updates
    //使用unsafe类进行cas
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //获取该值得偏移量(内存中的地址)
    private static final long valueOffset;
    /**
     * 内部使用int来做boolean的设置
     * 默认为0
     */
    private  volatile int value;
  1. serialVersionUID:序列化ID
  2. unsafe:该类是Atomic中核心类,用于执行低级别,对内存进行操作,内部都是native方法
  3. valueOffset:字段value的内存偏移地址
  4. value:真实value,1表示true 0表示false,使用volatile保证内存可见性

类初始化过程

    static 
        try 
           //返回对象成员属性在内存地址相对于此对象的内存地址的偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicBoolean.class.getDeclaredField("value"));
         catch (Exception ex)  throw new Error(ex); 
    

主要是通过unsafe方法获取value值得内存偏移地址

成员方法

get()

获取该boolean变量

    /**
     * 返回当前值
     */
    public final boolean get() 
        return value != 0;
    

boolean compareAndSet(boolean expect, boolean update)

比较前值后赋值,可能存在赋值失败的情况

     /*
      * 只有当期待的值为expect的时候才会更新相关值
      *  1. 期待的值等于现在值,则成功赋值,返回true
      *  2. 期待的值不等于现在的值,则赋值失败,则返回false
      */
    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);
    
  1. 将boolean转换成int类型
  2. 调用compareAndSwapInt进行CAS赋值
  3. 返回true则表示成功,false表示失败

boolean getAndSet(boolean newValue)

比较前值后进行赋值,用的相对较多

    public final boolean getAndSet(boolean newValue) 
        boolean prev;
        do 
            prev = get();
         while (!compareAndSet(prev, newValue));
        return prev;
    
  1. 先获取之前值
  2. 在调用循环compareAndSet进行CAS赋值

void set(boolean newValue)

无条件设置值,用的相对较少

    public final void set(boolean newValue) 
        value = newValue ? 1 : 0;
    

void lazySet(boolean newValue)

也是赋值操作,该操作会让Java插入StoreStore内存屏障,避免发生写操作重排序

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

总结

  1. 该类是原子性boolean类,是线程安全的
  2. 该原子类的核心操作都是基于Unsafe类
  3. CAS普遍会产ABA问题

以上是关于AQS源码解析-AtomicBoolean源码解析的主要内容,如果未能解决你的问题,请参考以下文章

AQS(AbstractQueuedSynchronizer)源码深度解析—AQS的设计与总体结构

AQS源码解析

AQS源码解析

提升--09---AQS源码解析

Java高并发学习——AQS及源码解析

AQS源码解析-CLH