AtomicInteger 源码解析(基于 JDK 1.8)

23 篇文章 1 订阅

1 介绍

AtomicInteger 是一个原子类,增加和删除是原子性的,避免外界直接使用 Unsafe 来实现原子操作。

实现原子性的原理是 CAS,具体可见我前面的文章。 unsafe 介绍(二)与CAS

成员变量 value 是 volatile 的,保证可见性。Volatile 介绍

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    private volatile int value;
  ...
}

下面的静态块,将 valueoffset 初始化了,其中AtomicInteger.class.getDeclaredField("value")返回一个表示 “value” 的Field,然后使用 unsafe.objectFieldOffset 获取相应的偏移位置,最后结果正好是 “value” 在 AtomicInteger 的偏移量。

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

2 初始化和 get/set

set 和 lazySet 的区别:

在 set 中,由于 value 是 volatile 修饰的,所以直接赋值 = ,可以写入到内存的,其他的线程立刻可见。

而 lazySet 调用了 unsafe 的 putOrderedInt,是 putIntVolatile 不保证可见性的版本,效果是可以加快处理速度。

在底层,set 相当于 volatile 写,会在前面插入一个 StoreStore屏障,后面插入一个 StoreLoad 屏障,禁止指令重排;而 putOrderedInt 不会在后面插入 StoreLoad,也就无法保证有序性和可见性。屏障的类型和作用可以见前面的文章:…

不建议使用 lazySet。

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) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

3 原子操作

compareAndSetweakCompareAndSet

weakCompareAndSet可能会虚假地返回 false,此时如果需要可以重试该操作,这依赖于当变量持有expectedValue 且没有其他线程也试图设置该变量时重复调用的保证,最终将成功。

此外,不提供同步控制需要的排序保证。

在 1.8 中,两者是一样的;在 1.9 中,方法加上 @HotSpotIntrinsicCandidate ,也就是可能由虚拟机 HotSpot 手动实现覆盖了这个方法。

官方注释可见下方代码。不建议使用 weakCompareAndSet。

下面的其他方法同样使用了 Unsafe 的 CAS 相关方法,如果函数名中 get 在前面,则先获取再修改,即返回旧值;否则,是先修改再获取,即返回新值。由于 CAS 中只有 get 在前面也就是返回旧值的方法,如果想返回新值,需要修改。

比如,当前值为 a,getAndIncrement将值修改为 a+1,并返回旧值 a;incrementAndGet将值修改为 a+1,返回新值 a+1。

由于底层都是 unsafe.getAndAddInt,返回的都是旧值 a,所以 incrementAndGet会在 return 处 +1。

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
/*
The atomic classes also support method weakCompareAndSet, which has limited applicability. On some platforms, the weak version may be more efficient than compareAndSet in the normal case, but differs in that any given invocation of the weakCompareAndSet method may return false spuriously (that is, for no apparent reason). A false return means only that the operation may be retried if desired, relying on the guarantee that repeated invocation when the variable holds expectedValue and no other thread is also attempting to set the variable will eventually succeed. (Such spurious failures may for example be due to memory contention effects that are unrelated to whether the expected and current values are equal.) Additionally weakCompareAndSet does not provide ordering guarantees that are usually needed for synchronization control. However, the method may be useful for updating counters and statistics when such updates are unrelated to the other happens-before orderings of a program. When a thread sees an update to an atomic variable caused by a weakCompareAndSet, it does not necessarily see updates to any other variables that occurred before the weakCompareAndSet. This may be acceptable when, for example, updating performance statistics, but rarely otherwise. 


*/
public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

//如果当前值为 a ,返回...
//将旧值 +1,返回 a
public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
//将旧值 -1,返回 a
public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
//将旧值 +delta,返回 a
public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
//将旧值 +1,返回 a+1
public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
//将旧值 -1,返回 a-1
public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
//将旧值 +delta,返回 a+delta
public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }


后面的四个方法同样是原子性的。符合我在 CAS 中所说的,在一个 do while 中,如果 while 的循环条件是一个 原子性的 CAS 操作,则不论循环体内部执行多复杂,整个方法都是原子性的。

在这里,next 是根据一个运算操作得到的值,这个操作应该尽可能简单,如果太复杂,可能被别的线程多次打断,很难完成 CAS 的操作,也就无法退出循环。

其中 IntUnaryOperator 是一元操作,即 y = f(x);IntBinaryOperator 是二元操作,即 z = f(x,y)。

/*下面是两个操作符的 lambda 示例
 IntUnaryOperator updateFunction = x-> {return 2*x;};
 IntBinaryOperator accumulatorFunction = (x,y)->{return x+y;};
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

public final int accumulateAndGet(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

下面是我的公众号,Java与大数据进阶,分享 Java 与大数据笔面试干货,欢迎关注
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值