java乐观锁之CAS原理解析

本文详细解析了Java中的CAS(Compare And Swap)机制,介绍了其在乐观锁中的应用。CAS操作包括比较内存位置的值与预期原值,如果匹配则更新为新值。文章讨论了CAS的CPU原语实现,以及其可能导致的ABA问题和解决策略。此外,还提到了由于循环重试可能带来的高开销和仅能保证单个共享变量原子性操作的限制。最后,通过AtomicInteger和AtomicReference等类的分析,展示了如何在实际编程中使用CAS。
摘要由CSDN通过智能技术生成

含义

CAS(CompareAndSwap) 即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。

乐观锁的含义就是假设没有发生冲突,那么我正好可以进行某项操作,如果要是发生冲突呢,那我就重试直到成功,乐观锁最常见的就是CAS。
无论是ReenterLock内部的AQS,还是各种Atomic开头的原子类,内部都应用到了CAS

原理分析

以java.util.concurrent.atomic.***AtomicInteger***为例进行分析

/**
 * An {@code int} value that may be updated atomically.  See the
 * {@link java.util.concurrent.atomic} package specification for
 * description of the properties of atomic variables. An
 * {@code AtomicInteger} is used in applications such as atomically
 * incremented counters, and cannot be used as a replacement for an
 * {@link java.lang.Integer}. However, this class does extend
 * {@code Number} to allow uniform access by tools and utilities that
 * deal with numerically-based classes.
 *
 * @since 1.5
 * @author Doug Lea
*/
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;
     /**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
   
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    ...
    }
  • Unsafe是位于sun.misc包下的一个类,Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。

在jdk1.9中,对Usafe进行了删除,因此那些基于Usafe开发的框架慢慢的都死掉了。

  • valueOffset是long类型的,此处代表的含义就是对象成员变量value相对对象内存地址的偏移量

valueOffset的赋值是放在static代码块中,也就是说类加载初始化的时候就执行一次,从而获取了value成员变量相对于当前对象内存地址的偏移量

  • value变量使用volatile修饰保证了内存可见性,为后面的CAS提供了可能性。其实实际存储的值是放在value中的
  • incrementAndGet方法剖析
    调用链:
    incrementAndGet() → unsafe.getAndAddInt(this, valueOffset, 1) + 1 → getAndAddInt(Object var1, long var2, int var4)
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;
    }

var1: 对应当前对象this; var2对应偏移量valueOffset;var4对应增量 1;
所以上面代码等价于

public final int getAndAddInt(Object this,long valueOffset,int 1){
   
    int var5;
    do {
   
        var5 = this.getIntVolatile(this, valueOffset);
    } while(!this.compareAndSwapInt(this, valueOffset
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值