深入理解锁

news2024/11/25 15:23:37

目录

常用锁策略

1.乐观锁 VS 悲观锁

2.轻量级锁 VS 重量级锁

3.自旋锁 VS 挂起等待锁

4.互斥锁 VS 读写锁

5.公平锁 VS 非公平锁

6.可重入锁 VS 可重入锁

CAS

ABA问题

Synchronized原理

1. 锁升级/锁膨胀

2.锁消除

3.锁粗化


常用锁策略

1.乐观锁 VS 悲观锁

站在锁冲突概率的预测角度.乐观锁预测冲突概率较小,悲观锁预测锁冲突概率较大

synchronized既是一个悲观锁,也是一个乐观锁.它默认是一个乐观锁,但当锁竞争比较激烈,就会变成悲观锁.

2.轻量级锁 VS 重量级锁

站在加锁操作的开销角度. 轻量级锁开销较小,重量级锁开销较大.

synchronized默认是一个轻量级锁,但发现锁竞争比较激烈的时候就会转转换成重量级锁.

3.自旋锁 VS 挂起等待锁

自旋锁是一种典型的轻量级锁,对于自旋锁,当锁被释放后,线程能第一时间感知到锁,从而有机会获取到锁

挂起等待锁是一种典型的重量级锁.当锁被释放后,继续等待,不知道什么时候能过获取到锁

synchronized这里的轻量级锁是基于自旋锁的方式实现的,而synchronized的重量级锁是针对挂起等待锁的方式实现的.

4.互斥锁 VS 读写锁

互斥锁提供加锁和解锁两种操作,如果一个线程加锁,另外一个线程也尝试加锁,就会产生阻塞等待.

读写锁提供了三种操作,分别是针对读操作加锁,针对写操作加锁和解锁操作.多线程针对同一个变量并发读,这个时候没有线程安全问题,也不需要加锁控制.

读锁和读锁之间没有互斥,写锁和写锁之间存在互斥,写锁和读锁之间存在互斥.

 synchronized不是读写锁

5.公平锁 VS 非公平锁

所谓公平,就是指 " 先来后到 ",下面举个栗子

 公平锁: 当女神分手后,由等待队列中最早来的舔狗上

 非公平锁: 就是当女神分手后,三个滑稽老铁都有了追求女神的机会,而和之前追了多长时间没有关系.

在操作系统和 Java synchronized 中都是非公平锁,操作系统针对加锁的控制,本身依赖线程的调度顺序,这个调度顺序是随机的,不会考虑线程等待了多长时间.

6.可重入锁 VS 可重入锁

不可重入锁: 一个线程针对一把锁,连续加锁两次出现死锁

可重入锁: 一个线程针对一把锁,连续加锁多次都不会死锁.

synchronized是可重入锁.

关于可重入问题和synchronized的相关操作

CAS

CAS指的是 compare and swap指的是 比较并交换,一个CAS涉及到一下操作:

上述这个CAS过程并非是通过异端代码实现的,而是通过一条 CPU指令完成的.而CAS操作是原子的,在一定程度上就回避了线程安全问题,同时在解决线程安全问题除了加锁之外,又可以使用CAS方法了.

CAS相当于通过一个原子的操作 , 同时完成 " 读取内存 , 比 较是否相等, 修改内存 " 这三个步骤 .

CAS可以实现原子类,在Java标准库中提供的类 

接下来用原子类写一个两个线程并发自加的操作

import java.util.concurrent.atomic.AtomicInteger;

    public static void main(String[] args) {
        //这些原子类,就是基于 CAS 实现了 自增,自减等操作
        //此时进行这类操作不用加锁也是线程安全的
        AtomicInteger count = new AtomicInteger(0);
        Thread t1 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();  //count++
                // count.incrementAndGet();  //++count
                // count.getAndDecrement();  //count--
                // count.decrementAndGet();  //count--
            }
        });
        Thread t2 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();  //count++
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(count.get());

    }

上面操作用伪代码进行实现

原子类这里的实现,每次修改之前,在确认一下这个值是否符合要求.

CAS还可以实现自旋锁

接下来看看CAS实现的自旋锁的伪代码

注意: 在java中并没有提供CAS方法,此处CAS相当于是一个简化的方式

ABA问题

CAS在运行中的核心是检查value和oldValue是否一致,如果一致,就视为value中途没有被修改过,在进行下一步操作,但可能在检查value和oldValue是否一致之前,可能会出现value从A修改成B,又从B修改为A这样的操作,CAS无法判断这种操作是否发生,这样的问题就叫ABA问题

针对这样的问题,采取的方案就是给要修改的数据加版本号,想象初始版本号是1,每次修改版本号都+1,人后进行CAS的时候,不是一以金额为基准了,而是以版本号为基准,因为版本号是只会自加的,而不会减少.

Synchronized原理

前面提到过,synchronized关键字,两个线程针对同一个线程加锁,就会产生阻塞等待.但在synchronized内部还有一些优化机制,存在的目的就是为了让锁更高效.

1. 锁升级/锁膨胀

通过Synchronized关键字进行加锁的的过程中,Synchronized会经历,无锁,偏向锁,轻量级锁,和重量级锁四种状态.

        第一个尝试加锁的线程,优先进入偏向锁的状态.

偏向锁不是真的 " 加锁 ", 只是给对象做一个 " 偏向锁的标记 ", 记录这个锁属于哪个线程 .
如果后续没有其他线程来竞争该锁 , 那么就不用进行其他同步操作了 ( 避免了加锁解锁的开销 )
如果后续有其他线程来竞争该锁 ( 刚才已经在锁对象中记录了当前锁属于哪个线程了 , 很容易识别 当前申请锁的线程是不是之前记录的线程), 那就取消原来的偏向锁状态 , 进入一般的轻量级锁状态 .
偏向锁本质上相当于 " 延迟加锁 " . 能不加锁就不加锁 , 尽量来避免不必要的加锁开销 .
但是该做的标记还是得做的 , 否则无法区分何时需要真正加锁 .
        当synchronized发生锁竞争的时候就会从偏向锁升级成轻量级锁,此时,synchronized相当于通过自旋的方式,来进行加锁的.(和上面CAS讲的伪代码一样).
        如果竞争进一步加强,自旋锁不能获取到当前锁状态,就会进入重量级锁.重量级锁是操作系统内核原生的API实现的,此时这个加锁功能就会影响到 线程的调度.如果线程进入重量级加锁,并且发生锁竞争,此时线程会被放到阻塞队列里,暂时不参与调度,直到锁被释放,才有机会被调度,并重新获取到锁.

2.锁消除

编译器智能的判定,看当前的代码是否真的要加锁,如果这个场景不需要加锁,而我们加了,编译器聚会自动把锁干掉.

3.锁粗化

锁的粒度: synchronized 包含的代码越多,粒度就越粗,包含的代码越少,粒度就越细.

通常情况下,认为锁的粒度细一点比较好,因为加锁部分的代码,是不能并发执行的,锁的粒度越细,能并发执行的代码就越多;反之,就越少.

但也有特殊的情况,有时候可能没有现成来抢占这个锁,jvm就会自动把锁粗化,避免频繁申请释放锁.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1217338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java实现图书管理系统】

图书管理系统 1. 设计背景2. 设计思路3. 模块展示代码演示3.1 Book类3.2 BookList类&#xff08;书架类&#xff09;3.4 用户类 - User类3.5 子类管理员类 -- AdminUser类3.6 子类普通用户类 -- NormalUser类3.7 操作接口3.8 操作类3.8.1 查找操作 -- FindOperation类3.8.2 增加…

PostgreSQL基于Citus实现的分布式集群

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

LCD1602指定位置显示字符串-详细版

本文为博主 日月同辉&#xff0c;与我共生&#xff0c;csdn原创首发。希望看完后能对你有所帮助&#xff0c;不足之处请指正&#xff01;一起交流学习&#xff0c;共同进步&#xff01; > 发布人&#xff1a;日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

Hive数据表操作--学习笔记

1&#xff0c;Hive数据表操作 1&#xff0c;建表语句和内外部表 ①创建内部表 create [external] table [if not exists] 表名( 字段名 字段类型 [comment 注释], 字段名 字段类型 [comment 注释], ... ) [row format delimited fields terminated by 指定分隔符];&#xff0…

深度学习之基于YoloV5血红细胞检测识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习已经在许多领域中得到了广泛的应用&#xff0c;包括医疗健康领域。其中&#xff0c;YOLO&#xff08;You O…

App加固中的代码混淆功能,让逆向工程师很头疼

App加固中的代码混淆功能&#xff0c;让逆向工程师很头疼 “我想离开浪浪山。” 在数次尝试破解某个App 时&#xff0c;某个逆向工程师无奈感慨道。 逆向工程师顾名思义就是把一个个完整的软件逆推&#xff0c;还原成一段段代码&#xff0c;方便破解。 比如给他们一个手机Ap…

行内样式、内部样式、外部样式

行内样式&#xff1a; 该元素的所在本行中使用style标记来写样式 内部样式&#xff1a; 在head标签中使用style标记来写样式 外部样式&#xff1a; 在head标签中使用link标记引用外部样式 注意优先级&#xff1a; 行内样式&#xff1e;内部样式&#xff1e;外部样式 代码…

ChatGPT简介及基本概念

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC &#x1f449;关于作者 专…

传输层——— UDP协议

文章目录 一.传输层1.再谈端口号2.端口号范围划分3.认识知名端口号4.两个问题5.netstat与iostat6.pidof 二.UDP协议1.UDP协议格式2.UDP协议的特点3.面向数据报4.UDP的缓冲区5.UDP使用注意事项6.基于UDP的应用层协议 一.传输层 在学习HTTP等应用层协议时&#xff0c;为了便于理…

JMeter JDBC请求---操作MySql数据库

准备&#xff1a; 1、MySql的驱动jar包&#xff1a;mysql-connector-java-5.1.28.jar&#xff0c; 2、jmeter安装目录中修改编码格式&#xff1a;\bin\jmeter.properties &#xff1a;sampleresult.default.encodingUTF-8 3、连接数据库的连接地址、用户名、密码以及操作s…

在test用户下创建test1表并插入数据,然后将tes1t表的查询权限授予test2用户

文章目录 1、以 test 用户登录2、创建 test1 表3、插入数据4、查看数据5、授予权限创建用户test2以 test 用户登录并授予权限&#xff1a;使用test2用户登录查询&#xff0c;测试结果 1、以 test 用户登录 首先&#xff0c;您需要以 test 用户登录到数据库 sqlplus test/1232…

RocketMQ 分布式事务消息实战指南:确保数据一致性的关键设计

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

【数据结构】树与二叉树(十七):二叉树的基础操作:删除指定结点及其左右子树(算法DST)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

【软考篇】中级软件设计师 第四部分(三)

中级软件设计师 第四部分&#xff08;三&#xff09; 三十四. 结构化开发方法34.1 内聚34.2 耦合 三十五. 测试基础知识三十六. 面向对象36.1 UML图36.2 设计模式36.3 数据流图 读前须知&#xff1a; 【软考篇】中级软件设计师 学前须知 上一章节&#xff1a; 【软考篇】中级软…

在rt-thread中使用iperf触发断言卡死

问题触发 最近在适配sdio device驱动&#xff0c;CP芯片与AP芯片对接&#xff08;RK3399&#xff09;&#xff0c;准备使用iperf测试下能否AP与CP能否正常通信。CP芯片跑的是rt-thread系统&#xff0c;在使用sdio_eth_dev_init命令初始化后&#xff0c;使用iperf -c 192.168.1…

Uniapp连接iBeacon设备——实现无线定位与互动体验(理论篇)

目录 前言&#xff1a; 一、什么是iBeacon技术 二、Uniapp连接iBeacon设备的准备工作 硬件设备&#xff1a; 三、Uniapp连接iBeacon设备的实现步骤 创建Uniapp项目&#xff1a; 四、Uniapp连接iBeacon设备的应用场景 室内导航&#xff1a; 五、Uniapp连接iBeacon设备的未来…

MQTT协议详解及在Android上的应用

MQTT协议详解及在Android上的应用 一、MQTT协议简介二、MQTT工作原理三、MQTT协议特点四、MQTT在Android上的应用4.1 准备工作4.2 示例代码 五、结论 本博客将全面介绍MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的基本概念、工作原理、特点以及在An…

网工内推 | 国企、上市公司售前,CISP/CISSP认证,最高18K*14薪

01 中电福富信息科技有限公司 招聘岗位&#xff1a;售前工程师&#xff08;安全&#xff09; 职责描述&#xff1a; 1、对行业、用户需求、竞争对手等方面提出分析报告&#xff0c;为公司市场方向、产品研发和软件开发提供建议&#xff1b; 2、负责项目售前跟踪、技术支持、需…

01Urllib

1.什么是互联网爬虫&#xff1f; 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那一台计算机上的数据便是蜘蛛网上的一个猎物&#xff0c;而爬虫程序就是一只小蜘蛛&#xff0c;沿着蜘蛛网抓取自己想要的数据 解释1&#xff1a;通过一个程序&#xff0c;根据Url(http://www.…

基于边缘智能网关的冬季管网智能监测应用

随着我国北方全面进入到冬季&#xff0c;多日以来严寒、降雪天气频发&#xff0c;民生基础设施也迎来冬季考验。尤其是民众生活仰赖的水、电、气管网&#xff0c;面临极端冰雪天气时易存在各种风险&#xff0c;包括管道水/气泄露损耗、低温冻裂、积雪压塌压损、冻结受阻等。 针…