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

深入理解CAS无锁机制与ABA的问题

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

深入理解CAS无锁机制与ABA的问题

CAS无锁机制

CAS简单的说,CAS需要你额外给出一个期望值(主内存中的现有值),也就是你认为这个变量现在应该是什么样子的;如果变量不是你想象的那样,那说明它已经被别人修改过了;你就要重新读取,再次尝试修改就好了。

(1)与锁相比,使用比较交换(下文简称CAS)会使程序看起来更加复杂一些。但由于其非阻塞性,它对死锁问题天生免疫,并且,线程间的相互影响也远远比基于锁的方式要小。更为重要的是,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,因此,它要比基于锁的方式拥有更优越的性能。

(2)无锁的好处:

第一,在高并发的情况下,它比有锁的程序拥有更好的性能;

第二,它天生就是死锁免疫的。

就凭借这两个优势,就值得我们冒险尝试使用无锁的并发。

(3)CAS算法的过程是这样:它包含三个参数CAS(V,E,N): V表示原有的值,E表示预期值,N表示新值。仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS返回当前V的真实值。

CAS操作是抱着乐观的态度进行的(乐观锁),它总是认为自己可以成功完成操作;当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败;失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作;基于这样的原理,

Cas  ABA的问题

Cas主要检查 内存值V与旧的预值值=E是否一致,如果一致的情况下,则修改。

这时候会存在ABA的问题:

如果将原来的值A,改为了B,B有改为了A 发现没有发生变化,实际上已经发生了变化,所以存在Aba问题。

解决办法:通过版本号码,对每个变量更新的版本号码做+1 

 --- 和预期值概念一样只不过是每修改成功一次后就将版本号递增+1;

CAS锁参数CAS(V,E,N)分别是value、expect、new的缩写
V:原有的值(存放在共享主内存中);
E:预期值(存放在当前线程的工作内存中)也就是说你认为原有值V是多少,后期会那E和V做比较,相等的话表示获取到了锁;
N:新值;

判断V==E:
如果不等于就表示主内存原有V值已被修改,需要重新获取预期值重新判断;
如果等于就表示主内存没有被其它线程操作过,将N新值替换到V原有值中。




CAS底层通过unsafe实现
  1. Java是通过unsafe jni技术调用C代码从而实现的CAS
  2. 原子类/自增类:AtomicInteger,AtomicLong,AtomicBoolean等都是使用 CAS 实现。 

     说明:unsafe类提供了专门用于原子性相关的标准方法,手写CAS也通过unasfe实现。

                AtomicInteger这些也都是调用的unsafe实现的原子递增。

原子类

使用AtomicInteger实现自增
public class Test002 extends Thread {
    // AtomicLong原子类默认从0开始
    private static AtomicLong atomicLong = new AtomicLong();

    @Override
    public void run() {
        while (atomicLong.get() < 10000) {
            // 递增+1
            long l = atomicLong.incrementAndGet();
            System.out.println(Thread.currentThread().getName() + "," + l);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Long startTime=System.currentTimeMillis();
        Test002 t1 = new Test002();
        Test002 t2 = new Test002();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        Long endTime=System.currentTimeMillis();
        System.out.println(endTime-startTime);
    }
}
 atomicLong.incrementAndGet();递增方法源码查看

 atomicLong.incrementAndGet()调用getAndAddLong方法进行递增,

  // var1=内存值、var6=旧的预期值 、var4=1

CAS(V, E, N)  三个参数对应关系:

var1 = V 内存值

var6 = E 旧的预期值

var6 + var4 = N 修改的新值

// var1=内存值、var6=旧的预期值 、var4=新值
// cas判断:var1==var6?var=var4:已被修改重新自旋
public final long getAndAddLong(Object var1, long var2, long var4) {
    long var6;
    // 进行CAS自旋-循环
    do {
    // 获取旧的预期值
    var6 = this.getLongVolatile(var1, var2);
    } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

    // 返回内存值
    return var6; 
}
基于Atomic原子类实现CAS无锁
public class AtomicTryLock {

    
    private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
    
    // 记录当前线程,只有当前线程才可释放锁
    private Thread lockCurrentThread;

    
    public boolean tryLock() {
        // compareAndSet(期望值, 修改值)
        boolean result = atomicInteger.compareAndSet(0, 1);
        if (result) {
            lockCurrentThread = Thread.currentThread();
        }
        return result;
    }

    
    public boolean unLock() {
        if (lockCurrentThread != null && lockCurrentThread != Thread.currentThread()) {
            return false;
        }
        return atomicInteger.compareAndSet(1, 0);
    }

    // 测试
    public static void main(String[] args) {
        // 创建自定义的锁
        AtomicTryLock atomicTryLock = new AtomicTryLock();
        // for循环创建10个线程
        IntStream.range(1, 10).forEach((i) -> new Thread(() -> {

            try {
                // 获取锁
                boolean result = atomicTryLock.tryLock();
                if (result) {
                    System.out.println(Thread.currentThread().getName() + ",获取锁成功~");
                } else {
                    System.out.println(Thread.currentThread().getName() + ",获取锁失败~");
                }
            } catch (Exception e) {
                e.printStackTrace();
                atomicTryLock.unLock();
            } finally {
                // 释放锁
                atomicTryLock.unLock();
            }

        }).start());
    }
}

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

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

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