java中CAS实现原理

java中在Unsafe中提供了三种CAS操作:

compareAndSwapInt(),compareAndSwapObject(),compareAndSwapLong()

//参数含义:对象,属性的内存偏移量,属性期望值,属性更新值
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

偏移量:内存中的对象包含对象头和对象实例数据,而对象头占8个字节,对于64位操作系统的压缩指针占4个字节, 所以我们一般说对象头占12个字节;例如对于一个test对象,x偏移量为这个对象的对象头即12个字节,y的偏移量为16

cas操作修改Test类的x变量。

public class CASTest {

    public static void main(String[] args) {
        Test test = new Test();
        Unsafe unsafe = UnsafeFactory.getUnsafe();
        long xOffset = UnsafeFactory.getFieldOffset(unsafe, Test.class, "x");
        System.out.println(xOffset); //12
        long yOffset = UnsafeFactory.getFieldOffset(unsafe, Test.class, "y");
        System.out.println(yOffset); //16
        unsafe.compareAndSwapInt(test, xOffset, 0, 1);
        System.out.println(test.x);
    }
    
    static class Test {
        int x;
        int y;
    }
}

CAS可以保证原子性,但是不能保证有序性和可见性,所以一般地,CAS配合volatile使用可以保证线程安全。底层最终通过执行一个cas指令(原子操作修改变量值),通过期望值和内存中的实际值进行比较,比较的结果如果相等则返回的是旧值(期望值)表示CAS操作成功,不相等则返回内存中实际值表示CAS操作失败。

CAS实现线程安全的操作

public class CASTest {

    private static int sum = 0;
    private static CASLock casLock = new CASLock();

    public static void main(String[] args) throws InterruptedException {
        for (int i=0; i<10; i++) {
            new Thread(() -> {
                for (;;) {
                    if (casLock.getState() == 0 && casLock.cas()) {
                        try {
                            for (int j = 0; j < 10000; j++) {
                                sum++;
                            }
                        } finally {
                            casLock.setState(0);
                        }
                        break;
                    }
                }
            }).start();
        }
        Thread.sleep(2000);
        System.out.println(sum);
    }
}
public class CASLock {

    private volatile int state = 0;
    private static final Unsafe UNSAFE;
    private static final long OFFSET;
    static {
        UNSAFE = UnsafeFactory.getUnsafe();
        OFFSET = UnsafeFactory.getFieldOffset(UNSAFE, CASLock.class, "state");
    }
    
    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public boolean cas() {
        return UNSAFE.compareAndSwapInt(this, OFFSET, 0, 1);
    }
}

jdk中juc包下原子类都是通过cas实现线程安全的。

ABA的问题可以通过版本号来解决

LongAdder、DoubleAdder原理

在高并发下,CAS操作会有大量的线程自旋,导致浪费线程资源,而为了提高执行效率,将V值拆分为多个变量,多个线程同时对各自的变量进行cas操作,所有线程执行完成后,将所有变量进行累加统计。其思想与jdk8中ConcurrentHashMap统计元素个数类似,LongAdder、DoubleAdder也实现了该思想。LongAdder中定义了base变量和cell数组变量,通过hash对Cell数组初始化和累加操作,最后将base和Cell数组所有的数进行累加得到结果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值