栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java原子类中CAS的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java原子类中CAS的使用

在多线程下,i++;操作不具有原子性,反汇编后i++由三步组成:取值,加操作,赋值.多线程造成累加不准确.
JUC包中原子类如何保证多线程下数据累加的准确性呢?

原子类原子操作的原理
  1. 首先,原子类中value属性通过volatile修饰,保证多线程间value的变化对其他线程是可见的;
  2. 其次,原子类中通过unsafe类获取value属性对应的内存偏移地址,即valueOffset
  3. 以AtomicInteger类的getAndSet方法举例,底层调用unsafe.getAndSetInt()
  4. 获取传入的实例this在valueOffset地址对应的值,即value属性的值,使用var5暂存,调用本地方法compareAndSwapInt(),通过this + valueOffset始终可以获取最新的value属性值,将value与var5对比,一致则将value值设置为 newValue,不一致则重新获取
  5. 原子类通过上述步骤避免多线程下数据不一致的问题.
源码说明
public class AtomicInteger extends Number implements java.io.Serializable {
    // ...
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
	// 获取value的内存地址,即valueOffset
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
	// volatile修饰value
    private volatile int value;

 public final int getAndSet(int newValue) {
 	// this 原子类实例,
	// value 属性的内存偏移地址,
	// newValue 待更新的值
 	return unsafe.getAndSetInt(this, valueOffset, newValue);
}

public final int getAndSetInt(Object var1, long var2, int var4) {
    int var5;
    do {
    	// 获取实例的value属性值
        var5 = this.getIntVolatile(var1, var2);
        // v1,v2始终可以获取最新的value属性值v_new,并传入当前value值v5用于对比,
        // v_new==v5,则将v4设为最新值,并返回true,跳出循环,否则重复
    } while(!this.compareAndSwapInt(var1, var2, var5, var4));

    return var5;
}
// compareAndSwapInt为native本地方法
// CPU层面调用CPU指令cmpxchg实现
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
小结

CAS可以理解成是一种思想或算法,即比较与交换.而JUC包下的原子类通过结合使用volatile ,unsafe类以及CAS(通过do while循环不断比较,与自旋锁的实现类似)来解决多线程下数据安全问题.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346231.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号