java 原子类的实现原理

2,453 阅读2分钟

一.原子类

  1. JDK并发包中的原子类包含AtomicBoolean,AtomicInteger,AutomicLong,AtomicReference以及相对应的数组类型。
  2. 修改原子类变量时无需加锁,非阻塞。

二.原理

AtomicInteger举例,类的成员变量

// Unsafe 类提供了硬件级别的原子操作。通过CAS原子操作实现变量更新
static final Unsafe unsafe = Unsafe.getUnsafe();
//获取变量的内存偏移动地址
private static final long valueOffset;
//要操作的变量变量,volatile保证可见性
private volatile int value;

构造方法

 /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /**
     * Creates a new AtomicInteger with initial value {@code 0}.
     */
    public AtomicInteger() {}

以原子方式实现对value操作的方法:

//以原子方式获取旧值并设置新值
public final int getAndSet(int newValue)
//以原子方式获取旧值并给当前值加1
public final int getAndIncrement()
//以原子方式获取旧值并给当前值减1
public final int getAndDecrement()
//以原子方式获取旧值并给当前值加delta
public final int getAndAdd(int delta)
//以原子方式给当前值加1并获取新值
public final int incrementAndGet()
//以原子方式给当前值减1并获取新值
public final int decrementAndGet()
//以原子方式给当前值加delta并获取新值
public final int addAndGet(int delta)

这些方法最终都过Unsafe类的compareAndSwapInt()方法实现变量的原子更新。比如getAndSet(int newValue)方法

public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }

 unsafe.getAndSetInt()方法实现如下:

public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }

当前对象var1通过存偏移地址var2获取更新前的值var5,compareAndSwapInt()原子操作,更新时判断更新前的var5是否和此时对象var1中的内存地址中的值相同,如果不同证明已被其他线程修改,返回false,反之讲值更新成要修改的值v4

getAndSetInt()方法中的while循环在没有更新成功时会不断尝试,直到更新成功。整个过程并没有发生阻塞,也没有加锁。其他方法更新过程类似。

三. ABA问题

其他原子类的原理与AtomicInteger原理类似。但是会产生ABA问题即当一个线程更新前检查值为A。另一个线程在该线程进行原子更新前,将值从A改成B又改回了A.该线程进行原子更新检查时察觉不到整个过程变化,原子更新成功。

ABA是不是一个问题与程序的逻辑有关,如果是一个问题,一个解决方法是使用AtomicStampedReference,在修改值的同时附加一个时间戳,只有值和时间戳都相同才进行修改。