首页 > 其他分享 >CAS无锁机制

CAS无锁机制

时间:2022-11-08 22:03:47浏览次数:40  
标签:无锁 return Thread CAS 修改 线程 内存 机制

1、 背景

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

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

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)

标签:无锁,return,Thread,CAS,修改,线程,内存,机制
From: https://www.cnblogs.com/pinp/p/16860926.html

相关文章

  • grafana agent 动态配置内部机制简单说明
    grafanaagent动态配置目前属于一个体验特性,但是设计上利用了gomplate一个强大的模版引擎工具参考配置运行配置参考agentv2:image:grafana/agent:ma......
  • CF460C Present & CF954G Castle Defense
    没错是双倍经验。题意:一个长度为\(n\)的序列\(a\),你有\(m\)次操作的机会,每次操作是将其中连续的\(w\)个元素增加\(1\)。最大化最终序列的最小值。\(1\leqw......
  • RabbitMQ的消息确认ACK机制
    ACK机制由于通信过程的不可靠性,传输的数据不可避免的会出现丢失、延迟、错误、重复等各种状况,TCP协议为解决这些问题设计了一系列机制。这个机制的核心,就是发送方向接收方发......
  • RabbitMQ3/4---持久化机制、内存磁盘控制
    1.RabbitMQ持久化机制RabbitMQ持久化机制分为队列持久化、消息持久化、交换器持久化。不管是持久化的消息还是非持久化的消息都可以被写入到磁盘。(1)RabbitMQ队列持久化队列......
  • logrotate机制与原理
    日志实在是太有用了,它记录了程序运行时各种信息。通过日志可以分析用户行为,记录运行轨迹,查找程序问题。可惜磁盘的空间是有限的,就像飞机里的黑匣子,记录的信息再重要也只能记......
  • oracle case when 用法总结
    ​​Oracledbms_jobpackage用法小结​​ORACLECASEWHEN及SELECTCASEWHEN的用法  Case具有两种格式。简单Case函数和Case搜索函数。--简单case函数casesex......
  • python二机制文件解析
    参考连接:https://blog.csdn.net/lovelyaiq/article/details/81988185C语言解析:#include"stdlib.h"#include"stdio.h"typedefunsignedintuint32_t;typedefunsi......
  • shell编程 判断结构语句(if、case)
    一、if语句if语句通过关系运算符判断表达式的真假来决定执行哪个分支。Shell有三种if...else语句:if...fi语句;if...else...fi语句;if...elif...else......
  • Open Cascade 7.7.0 新功能:BRepLib_PointCloudShape
    ​ 1.简介OCC官方在2022年10月3日发布7.7Beta版,并于今天2022年11月7日正式发布OpenCascade7.7.0版本,其中一个更新为:一个用于生成拓扑模型上的点集的工具方法。......
  • jvm双亲委派机制详解
    双亲委派机制​ 记录一下JVM的双亲委派机制学习记录。类加载器种类​ 当我们运行某一个java类的main方法时,首先需要由java虚拟机的类加载器将我们要执行的main方法所......