侧边栏壁纸
博主头像
一定会去到彩虹海的麦当

说什么呢?约定好的事就一定要做到啊!

  • 累计撰写 63 篇文章
  • 累计创建 16 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

AtomicInteger原子操作类

一定会去到彩虹海的麦当
2022-07-28 / 0 评论 / 0 点赞 / 93 阅读 / 1,795 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-07-28,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

原子性

即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

int++ 并不是一个原子操作,所以当一个线程读取它的值并加 1 时,另外一个线程有可能会修改原来的int值,这就会引发错误。

原子类

java.util.concurrent 这个包里面提供了一组原子类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,然后由 JVM 从等待队列中选择一个线程进入,这只是一种逻辑上的理解。

原子类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference

原子数组:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray

原子属性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater

解决 ABA 问题的原子类:AtomicMarkableReference(通过引入一个 boolean 来反映中间有没有变过),AtomicStampedReference(通过引入一个 int 来累加来反映中间有没有变过)

AtomicInteger 原理

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;

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

    private volatile int value;
}

AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。

CAS 的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。

UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到 value属性的内存地址,返回值是 valueOffset,我们可以通过这个valueOffset访问value属性。

另外 value 是一个 volatile 变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。

Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得。jdk8直接调用Unsafe.getUnsafe()获得的unsafe。

public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

//unsafe.getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        //获取共享变量旧值
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

compareAndSwapInt()包含三个操作数:

内存位置(var2)、预期原值(var5)和新值( var5 + var4)

如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则会自旋直到成功。

0

评论区