【源码】JUC —— AtomicInteger 解读

前言

atomic
JUC 下提供了大量的 原子操作类,以保证我们可以便捷的操作对应类型且保证 并发环境 下的 原子性。本章节解读 AtomicInteger

版本

JDK11

Unsafe

底层的操作基本都由 Unsafe 类提供,比如 CAS操作

	@HotSpotIntrinsicCandidate
    public final native boolean compareAndSetInt(Object o, long offset,
                                                 int expected,
                                                 int x);

使用 native 方法调用 CPU指令(譬如 cmpxchg ) 实现 CAS 操作CAS(compare and swap 比较和交换),简单地描述就是:

在对操作数执行变更后,写入内存前先将原操作数和内存中当前操作数进行 compare

如果相同,则表明此次更新有效,然后将更新后的结果与当前内存中的原操作数进行 swap

compare and swap,而整个 CAS操作 基于一个 CPU指令 实现,因此保证了 原子性

比如在上述方法中各参数的意义

  • Object o:更新对象
  • long offset:对应更新字段的 偏移量(用于定位字段)
  • int expected:预期的原操作数值
  • int x:被更新成的目标值

AtomicInteger

AtomicInteger ,基于 int 型变量的 原子操作类

属性及构造

	// Unsafe
	private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();

	// 字段偏移量
    private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");

	// 默认为 0
    private 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;
    }

接受一个 int 值作为初始 valuevaluevolatile 关键字修饰用于保证 并发环境 下的 可见性

原子操作

分析几个核心的 原子操作 方法

getAndSet

	// 更新并返回更新前的值
	public final int getAndSet(int newValue) {
        return U.getAndSetInt(this, VALUE, newValue);
    }

	----------------------Unsafe---------------------

	@HotSpotIntrinsicCandidate
    public final int getAndSetInt(Object o, long offset, int newValue) {
        int v;

		// 自旋,直到 CAS 成功
        do {
            v = getIntVolatile(o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, newValue));
        return v;
    }

	@HotSpotIntrinsicCandidate
    public native int     getIntVolatile(Object o, long offset);

	@HotSpotIntrinsicCandidate
    public final boolean weakCompareAndSetInt(Object o, long offset,
                                              int expected,
                                              int x) {
        // CAS native 方法
        return compareAndSetInt(o, offset, expected, x);
    }

	@HotSpotIntrinsicCandidate
    public final native boolean compareAndSetInt(Object o, long offset,
                                                 int expected,
                                                 int x);

更新 oldValuenewValue,并返回 oldValue,底层依赖一段 自旋 操作,即可以理解为:不停地 CAS 直到成功

compareAndSet

	public final boolean compareAndSet(int expectedValue, int newValue) {
        return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
    }

AtomicInteger 同时也对外暴露了 CAS方法

getAndXXX

	// 递增 1 并返回 oldValue
	public final int getAndIncrement() {
        return U.getAndAddInt(this, VALUE, 1);
    }

	// 递减 1 并返回 oldValue
    public final int getAndDecrement() {
        return U.getAndAddInt(this, VALUE, -1);
    }

	// 递增 delta 并返回 oldValue
    public final int getAndAdd(int delta) {
        return U.getAndAddInt(this, VALUE, delta);
    }

	-----------------------Unsafe-------------------

	// 自旋
	@HotSpotIntrinsicCandidate
    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, v + delta));
        return v;
    }

依赖 自旋 + CAS,更新 oldValuenewValue,并返回 oldValue

XXXAndGet

	public final int incrementAndGet() {
        return U.getAndAddInt(this, VALUE, 1) + 1;
    }

    public final int decrementAndGet() {
        return U.getAndAddInt(this, VALUE, -1) - 1;
    }

    public final int addAndGet(int delta) {
        return U.getAndAddInt(this, VALUE, delta) + delta;
    }

getAndXXX 类似,不同的是返回 newValue

Update

	public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev = get(), next = 0;
	
		/**
         * 自旋
         * 修改 prev 为 next
         * CAS 更新
         * 更新失败且 oldPrev == newPrev,继续 CAS 更新
         * 更新失败且 oldPrev != newPrev,修改 newPrev 为 next 再 CAS 更新
         * 返回 prev
         */
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.applyAsInt(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return prev;
            haveNext = (prev == (prev = get()));
        }
    }

	// 返回 next
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.applyAsInt(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return next;
            haveNext = (prev == (prev = get()));
        }
    }

	---------------IntUnaryOperator---------------

	// 函数式接口,接受一个 int 参数,返回一个 int
	@FunctionalInterface
	public interface IntUnaryOperator {

	    int applyAsInt(int operand);
	
		//	 略

	}

接受 自定义函数 更新 value,底层也是基于 自旋 + CAS

Accumulate

	public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = accumulatorFunction.applyAsInt(prev, x);
            if (weakCompareAndSetVolatile(prev, next))
                return prev;
            haveNext = (prev == (prev = get()));
        }
    }

    public final int accumulateAndGet(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = accumulatorFunction.applyAsInt(prev, x);
            if (weakCompareAndSetVolatile(prev, next))
                return next;
            haveNext = (prev == (prev = get()));
        }
    }

	-----------------IntBinaryOperator---------------

	// 接受两个 int 参数,返回一个 int
	@FunctionalInterface
	public interface IntBinaryOperator {
	
	    int applyAsInt(int left, int right);
	}

updateAndGet getAndUpdate 方法类似,只是该 函数接口 接受两个 int 参数,返回一个 int

类型转换

	public int intValue() {
        return get();
    }

    public long longValue() {
        return (long)get();
    }

    public float floatValue() {
        return (float)get();
    }

    public double doubleValue() {
        return (double)get();
    }

同时也提供了各种 类型转换 的方法

demo

public class AITest {

    static AtomicInteger atomicInteger = new AtomicInteger(0);
    static CountDownLatch countDownLatch = new CountDownLatch(100);

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 100; i++) {
            Thread t = new Thread(() -> {
                atomicInteger.incrementAndGet();
                countDownLatch.countDown();
            });
            t.start();

        }

        // 主线程 wait 等待子线程 CAS 完成后 countDown
        countDownLatch.await();

        // 保证了所有 CAS 完成后才输出
        System.out.println(atomicInteger.get());
    }
}

结果:
100

其他原子类

事实上,其他 原子类 比如 AtomicReference AtomicReferenceArray 等的原理基本也是如此,细节上不同的是其他类在 JAVA9 以后是基于 句柄变量VarHandle 进行 属性获取、CAS 等操作的

关于 句柄变量VarHandle,可自行了解

比如在 AtomicReference


	// 句柄变量
	private static final VarHandle VALUE;

	// 基于 LookUp 赋值句柄变量
    static {
        try {
            MethodHandles.Lookup l = MethodHandles.lookup();
            VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
        } catch (ReflectiveOperationException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private volatile V value;

	--------------------CAS--------------------------

	// 基于 VarHandle 的 CAS
	public final boolean compareAndSet(V expectedValue, V newValue) {
        return VALUE.compareAndSet(this, expectedValue, newValue);
    }

其实在本质上,都是一样的

总结

原子操作类 在日常开发中也会经常用的,为我们提供了便捷安全的方法保证我们在 并发环境 下保证变量的 原子性,十分实用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值