Java并发编程—AtomicInteger 原理剖析

3,366 阅读2分钟

一、前言

AtomicInteger 是一个支持原子操作的 Integer 类,它提供了原子自增方法、原子自减方法以及原子赋值方法等。其底层是通过 volatile 和 CAS 实现的,其中 volatile 保证了内存可见性,CAS 算法保证了原子性。因此接下来我们先了解下 volatile 和 CAS,然后在研究下 AtomicInteger 的源码。

二、volatile 变量

volatile 是一种稍弱的同步机制,用来确保将变量的更新操作通知到其他线程。当把变量声明为 volatile 类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile 变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取 volatile 类型的变量时总返回最新写入的值。在访问 volatile 变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此 volatile 变量是一种比 sychronized 关键字更轻量级的同步机制。

三、CAS

CAS(Compare And Swap)即比较并交换,CAS 是乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。它包含三个参数:V 内存值,预期值 A,要修改的新值 B。当且仅当预期值 A 和内存值 V 相同时,将内存值 V 修改为 B,否则什么都不做。原理图如下所示:


四、AtomicInteger 源码剖析

private static final Unsafe unsafe = Unsafe.getUnsafe();//调用指针类Unsafe
private static final long valueOffset;//变量value的内存偏移量

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

private volatile int value;//volatile修饰的int变量value
public AtomicInteger(int initialValue) {//带参数的构造函数
    value = initialValue;
}

public AtomicInteger() {//不带参数的构造函数
}
public final int get() {//获取当前最新值
    return value;
}


public final void set(int newValue) {//设置当前值
    value = newValue;
}
public final void lazySet(int newValue) {//最终把值设置为newValue,使用该方法后,其他线程在一段时间内还会获取到旧值
    unsafe.putOrderedInt(this, valueOffset, newValue);
}


public final int getAndSet(int newValue) {//设置新值并返回旧值
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}
public final boolean compareAndSet(int expect, int update) {//如果当前值为expect,则设置为update
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final int getAndIncrement() {//当前值加1返回旧值
    return unsafe.getAndAddInt(this, valueOffset, 1);
}


public final int getAndDecrement() {//当前值减1返回旧值
    return unsafe.getAndAddInt(this, valueOffset, -1);
}


public final int getAndAdd(int delta) {//当前值增加delta,返回旧值
    return unsafe.getAndAddInt(this, valueOffset, delta);
}


public final int incrementAndGet() {//当前值增加1返回新值
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}


public final int decrementAndGet() {//当前值减1,返回新值
    return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}

五、总结

使用 AtomicInteger 替换普通 int 类型执行自增的原子操作,能够保证了线程安全。