1、 背景

  传统Synchronized锁:悲观,如果没有获取到锁的情况下,会让当前线程变为阻塞的状态,释放CPU执行权,效率非常低。

  乐观锁(自旋):本质上没有锁,没有死锁现象,而且效率比较高,不会释放CPU执行权,自旋并通过预值比较或版本号控制。

2、原理

  CAS的英文全称是CompareAndSet,也就是比较然后修改,涉及到三个值,V、E和N,V是主内存的共享变量值,E是工作内存的副本值,N是修改内存的值。关于内存值的修改,有两种情况:第一种情况是比较V和E的值,如果相等,则对V进行修改;第二种情况是V和E不等,说明有线程已经修改过了,那就重新读取主内存的值,再做判断、修改。
V=内存值(主内存值);E=预期值(工作内存值) ;N=新值(需要修改的值)
  第一种情况:(V未被修改)
    第一步:读取主内存值V,复制给E
    第二步:判断V的值,如果V==E,说明共享变量的V没有被修改
    第三步:将V的值改为N
  第二种情况:(V被修改)
    第一步:读取内存之V,复制给E
    第二步:判断V的值,如果V!=E,说明别的线程修改了共享变量的V
    第三步:重新读取主内存V的值给E
    第四步:修改时再判断V的值是否等于E,如果不等,继续自旋,直至相等再将V的值修改为N。

  注意:不可能有两个线程同时修改V的值,因为CAS底层通过指令控制了原子性。

3、应用场景

  Java UNSAFE类
  原子类 Atomic

4、利用CAS原子类方式实现一个锁

 1 public class AtomicTryLock {
 2 
 3     /**
 4      * 定义AtomicInteger  修改为1表示该锁已经被使用该 修改为0表示为被使用
 5      */
 6     private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
 7     private Thread lockCurrentThread;
 8 
 9     /**
10      * 尝试获取锁
11      *
12      * @return
13      */
14     public boolean tryLock() {
15         boolean result = atomicInteger.compareAndSet(0, 1);
16         if (result) {
17             lockCurrentThread = Thread.currentThread();
18         }
19         return result;
20     }
21 
22     /**
23      * 释放锁
24      *
25      * @return
26      */
27     public boolean unLock() {
28         if (lockCurrentThread != null && lockCurrentThread != Thread.currentThread()) {
29             return false;
30         }
31         return atomicInteger.compareAndSet(1, 0);
32     }
33 
34     public static void main(String[] args) {
35         AtomicTryLock atomicTryLock = new AtomicTryLock();
36         IntStream.range(1, 10).forEach((i) -> new Thread(() -> {
37 
38             try {
39                 boolean result = atomicTryLock.tryLock();
40                 if (result) {
41                     System.out.println(Thread.currentThread().getName() + ",获取锁成功~");
42                 } else {
43                     System.out.println(Thread.currentThread().getName() + ",获取锁失败~");
44                 }
45             } catch (Exception e) {
46                 e.printStackTrace();
47                 atomicTryLock.unLock();
48             } finally {
49                 atomicTryLock.unLock();
50             }
51 
52         }).start());
53     }
54 }

5、如何解决CAS产生的ABA问题

5.1 什么是ABA问题

  如果【线程1】将原来的值A,改为了B,【线程2】B又改为了A 发现没有发生变化,实际上已经发生了变化,但是【线程3】修改时判断V值没有发生变化,这种现象为ABA

5.2 解决办法

  通过版本号码,对每个变量更新的版本号码做+1

来源:蚂蚁课堂(mayikt.com)

posted on 2022-12-06 08:57  梧桐i  阅读(221)  评论(0)    收藏  举报