当前位置: 首页 > article >正文

实现CAS自旋锁

CAS

  • 在高并发场景,可以使用加锁、CAS来保证原子性,但是加锁是很重量级的操作,CAS类似于乐观锁
  • CAS ( Compare and swap )比较并交换,是实现并发算法时常用到的技术,包含三个操作数:内存位置、预期原值、更新值
  • 执行CAS操作的时候,将内存位置中的值与预期原值比较
    • 如果匹配,会将该位置的值更新为新值,
    • 如果不匹配就不会做任何操作,或者重试,这种重试被称为自旋,多个线程同时执行CAS操作,只有一个会成功
  • CAS 是JDK提供的非阻塞原子操作,通过硬件保证了比较-更新的原子性
  • CAS 是一种系统原语,原语属于操作系统用于范畴,由若干条指令组成,用于完成某个功能,原语的执行必须是连续的,在执行过程中不允许被中断,所以说CAS是一条CPU的原子指令,不会造成数据不一致的问题
  • JDK提供的CAS机制,在汇编层级会禁止变量两侧的指令优化,然后使用 cmpxchg(比较并交换) 指令比较并更新变量值
  • 执行 cmpxchg 指令的时候,会判断当前系统是否为多核系统,
    • 如果是就给总线加锁,只有一个线程可以对总线加锁成功,加锁成功后执行CAS操作
    • 所以CAS的原子性实际上是CPU实现独占的,比起synchronized,CAS的排他时间要短很多,多线程情况下性能会更好

CAS自旋锁

  • CAS利用CPU的指令保证了操作的原子性,达到锁的效果
  • 自旋锁也就是获取锁失败的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,直到成功获取锁,或者超时,放在CAS就是执行一个CAS操作,不断的去执行CAS操作,直到CAS操作被成功执行
  • 这样的好处是减少了线程上下文的切换,缺点是循环会消耗CPU

示例:不通过 synchronized 和 lock ,就实现了锁的功能

public class Caslock {
    
    //是否加锁,初始值为 false,也就是未加锁
    private AtomicBoolean atomicBoolean =new AtomicBoolean(false);
    
    public void lock(){
        System.out.println(Thread.currentThread().getName()+",尝试加锁");
        //原子布尔的值是否是false,是就加锁,把值改为true,不是就释放锁
        while (!atomicBoolean.compareAndSet(false,true)){
            //不是false,加锁失败,由其他线程先加了锁,这里就需要等待
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println(Thread.currentThread().getName()+",加锁成功");
    }
    public void unLock(){
        //解锁,把值设为 false
        atomicBoolean.compareAndSet(true,false);
        System.out.println(Thread.currentThread().getName()+",释放锁");
    }
}


    private static void testCasLock() throws Exception{
        Caslock caslock = new Caslock();
        new Thread(()->{
            caslock.lock();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            caslock.unLock();
        },"线程A").start();

        Thread.sleep(500);
        new Thread(()->{
            caslock.lock();
            caslock.unLock();
        },"线程B").start();
    }

-- 执行结果是:
    
线程A,尝试加锁
线程A,加锁成功
线程B,尝试加锁
线程A,释放锁
线程B,加锁成功
线程B,释放锁    


http://www.kler.cn/a/135871.html

相关文章:

  • 5G -- 5G网络架构
  • SpringBoot相关漏洞学习资料
  • javaEE-线程的常用方法-4
  • Redis 集群实操:强大的数据“分身术”
  • Android Studio IDE环境配置
  • 深度学习的DataLoader是什么数据类型,为什么不可用来索引
  • 工程项目立项需要做哪些准备?
  • 视频转码方法:多种格式视频批量转FLV视频的技巧
  • 【Linux网络】详解使用http和ftp搭建yum仓库,以及yum网络源优化
  • git常用命令和参数有哪些?【git看这一篇就够了】
  • 【开题报告】基于SpringBoot的网上摄影工作室的设计与实现
  • 前端面试考核点【更持续新中】
  • 根据nginx日志统计页面访问次数
  • 指针变量和地址
  • 11.1 文件拷贝移动与删除
  • 【Java】异常处理(一)
  • K8S基础笔记
  • 极域电子教室-教师机无法找到学生机
  • ArcEngine:如何进行缩放图层、属性信息显示、状态栏显示?
  • 关于这个“这是B站目前讲的最好的【Transformer实战】教程!“视频的目前可以运行的源代码GPU版本
  • 采集1688整店商品(店铺所有商品、店铺列表api)
  • 北京君正客户应用案例:掌静脉3D人脸猫眼视屏智能锁
  • 信息机房监控系统(动环辅助监控系统)
  • 4种经典的限流算法与集群限流
  • MAC地址_MAC地址格式_以太网的MAC帧_基础知识
  • IDEA运行thymeleaf的html文件打开端口为63342且连不上数据库