【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)

目录

1、锁的策略

1.1、乐观锁和悲观锁 

1.2、轻量级锁和重量级锁

1.3、自旋锁和挂起等待锁

1.4、普通互斥锁和读写锁

1.5、公平锁和非公平锁

1.6、可重入锁和不可重入锁 

2、synchronized 内部的升级与优化过程

2.1、锁的升级/膨胀

2.1.1、偏向锁阶段

2.1.2、轻量级锁阶段

2.1.3、重量级锁阶段

2.2、锁消除

2.3、锁粗化

3、CAS(Compare and swap)

3.1、CAS 的应用

3.1.1、实现 Atomic 原子类

3.1.2、实现自旋锁

3.1.3、CAS 的 ABA 问题



1、锁的策略

加锁过程中,处理冲突的过程中,涉及到的一些不同的处理方式,就叫锁的策略。

1.1、乐观锁和悲观锁 

乐观锁
在加锁之前,预估当前出现锁冲突的概率不大,因此在进行加锁的时候就不会做太多的工作。

由于加锁过程中做的事情比较少,加锁的速度可能就更快,但是更容易引入一些其他的问题(消耗更多cpu资源)。


悲观锁
在加锁之前,预估当前出现锁冲突的概率比较大,因此在进行加锁的时候就会做更多的工作。

由于加锁过程中做的事情更多,加速的速度可能更慢,但是整个过程中不容易出现其他问题

1.2、轻量级锁和重量级锁

轻量级锁
加锁的开销小,加锁的速度更快, 轻量级锁,一般就是乐观锁。


重量级锁
加锁的开销更大,加锁的速度更慢,重量级锁,一般就是悲观锁。

需要注意的是: 

悲观乐观,是在加锁之前,对未发生的事情进行的预估。
轻量重量,是在加锁之后,对结果的评价。
但是整体来说,这两种角度,描述的都是同一个事情。 

1.3、自旋锁和挂起等待锁

自旋锁
就是轻量级锁的一种典型实现,同时也是一种乐观锁。
进行加锁的时候,会搭配一个while循环,如果加锁成功,自然循环结束。
如果加锁不成功,不是阻塞放弃cpu,而是进行下一个循环,再次尝试获取到锁。
上述操作的反复快速执行的过程,就称为“自旋”。一旦其他线程释放了锁,就能第一时间拿到锁。


挂起等待锁
就是重量级锁的一种典型实现,同时也是一种悲观锁(适用于锁冲突激烈的情况)。

1.4、普通互斥锁和读写锁

普通互斥锁
类似于 synchronized 操作涉及的 加锁 和 解锁


读写锁
把加锁分为两种情况: 1)加读锁 ReadLock 2)加写锁 WriteLock
结论:读锁与读锁不会出现锁冲突(不会阻塞),写锁与写锁、读锁与写锁都会出现锁冲突(会阻塞)
这里的差异理解起来也很简单,因为两个线程进行读操作,本身就是线程安全的,所以不需要进行互斥(而且读操作在实际开发中有非常频繁,所以能够大大提升了性能), synchronized 不是读写锁,对于读写锁 JVM 同样封装了 api 给程序员使用。

1.5、公平锁和非公平锁

公平锁
先来后到叫公平,实现公平锁需要引入额外的数据结构(队列,记录先后顺序)。


非公平锁
Java中默认的锁就是非公平锁,正是因为非公平锁导致了“线程饿死”

所谓“线程饿死”,可以理解为:

        当线程A获取锁时,发现此时不能完成实质性的逻辑(取钱时发现atm没钱了),此时只能释放锁并退出,重新与其他线程竞争该锁(刚刚释放锁的线程也会参与到锁竞争中)。有一个极端情况,就是每次释放锁之后又是线程A获取到了锁,并且此时依然无法完成实质性的逻辑,又只能释放锁。就出现【线程A忙了半天不干实事,其他线程都只能干等了】的情况,这就称之为“线程饿死”。
        而这种极端情况出现的概率还挺高的,因为线程A获取锁后处在RUNNABLE状态,而其他线程处在BLOCKED状态,处于BLOCKED状态的线程需要系统唤醒之后才能参与锁竞争,而线程A不需要,因此线程A再次获取到锁的概率比其他的线程高。

1.6、可重入锁和不可重入锁 

针对一个线程一把锁,连续加锁两次不会产生死锁,就是可重入锁,反之就是不可重入锁。系统自带的锁是不可重入锁,Java 的 synchronized 是可重入锁。

2、synchronized 内部的升级与优化过程

Java 中的 synchronized 具有自适应能力。内部会自动评估当前锁冲突的剧烈程。

如果当前锁冲突的剧烈程度不大,就处在 乐观锁/轻量级锁/自旋锁。

如果当前锁冲突的剧烈程度很大,就处在 悲观锁/重量级锁/挂起等待锁。

2.1、锁的升级/膨胀

2.1.1、偏向锁阶段

类似于“懒汉模式”,能不加锁就不加锁,能晚加锁就晚加锁。在遇到竞争的情况下,偏向锁没有提高效率;但是如果在没有竞争的情况下, 偏向锁就大幅度的提高了效率。

.

【只是做了一个标记,没有真加锁(也就不存在互斥),一旦有其他线程想要来竞争锁,就在另一个线程之前先把锁获取到,进而从偏向锁升级到轻量级锁(存在互斥)。】

2.1.2、轻量级锁阶段

通过自旋锁的方式来实现优势:其他线程释放锁后能够第一时间拿到锁;劣势:消耗cpu;

.

此外 synchronized 内部也会统计当前这个锁对象上,有多少个线程产于竞争(都是自旋式竞争),如果发现参与竞争的线程比较多,就会进一步升级到重量级锁。

2.1.3、重量级锁阶段

此时拿不到锁的线程就不会继续自旋,而是进入“阻塞等待”,让出cpu资源。锁被释放后回归随机唤醒机制。

2.2、锁消除

简单来说就是自动干掉不必要的锁。

2.3、锁粗化

简单来说就是把多个细粒度的锁合并成一个粗粒度的锁,减少锁竞争的开销。

以上说的所有机制,都是在内部自动执行的,不需要程序员在编写代码的时候真正的手动执行。

3、CAS(Compare and swap)

CAS(即比较并交换)本身是特殊的单个 cpu 指令,一个 CAS 涉及以下操作:

假设内存中的原数据V,旧的预期值A,需要修改的新值B

1、比较A与V是否相等(比较)

2、如果比较相等,将B写入V(交换)

3、返回操作是否成功

由于 CAS是单个 cpu 指令,使用 CAS 可以“原子”的完成很多复杂操作,不涉及到加锁,也不会阻塞,合理的使用也可以保证线程安全,使用 CAS 的编程方式称为“无锁化编程”,是多线程编程中的特殊技巧。

操作系统对 CAS 指令进行了封装成了 api ,JVM 有对操作系统提供的 api 又封装一层。

3.1、CAS 的应用

3.1.1、实现 Atomic 原子类

Java 标准库中的 Atomic 原子类就是基于 CAS 来实现的。

伪代码描述 CAS 以及 模拟 AtomicInteger 自增过程

3.1.2、实现自旋锁

伪代码描述自旋锁的执行过程

3.1.3、CAS 的 ABA 问题

CAS 使用的时候,关键要点是判定当前内存的值和寄存器中的值是否一样,判定是否一样的操作本质上是在判定这个代码执行的过程中是否有其他线程穿插进来了。

但是这样的判定可能存在这样的可能,本来数值是0,执行 CAS 之前,另一个线程把值从 0 → 100 ,又从 100 → 0 ,虽然改了,但是又改回去了,这种情况就称为 ABA 问题。CAS 的 ABA 问题一般情况下不会有问题,不会产生啥 bug ,但是就怕一些极端情况。

解决方案:
1、约定数据变化是单向的(只能添加或者只能减少),不能是双向的。
2、对于本身就必须双向变化的数据,可以引入一个版本号,版本号是单向增加的。

【博主推荐】 

【Java多线程】对线程池的理解并模拟实现线程池-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136160003?spm=1001.2014.3001.5501【Java多线程】分析线程加锁导致的死锁问题以及解决方案-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136150237?spm=1001.2014.3001.5501【Java多线程】线程安全问题与解决方案-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136133785?spm=1001.2014.3001.5501

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

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

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

相关文章

[CISCN 2019华东南]Web11

打开题目 看到xff就应该想到抓包 看回显也是127.0.0.1,我们盲猜是不是ssti模板注入 输入{{7*7}}显示49 可以看的出来flag在根目录下 输入{system(‘cat /flag’)} 得到flag 知识点: 漏洞确认 一般情况下输入{$smarty.version}就可以看到返回的smarty…

个人玩航拍,如何申请无人机空域?

我们在《年会不能停》一文中,有分享我们在西岭雪山用无人机拍摄的照片和视频,有兴趣可以去回顾。 春节的时候,趁着回老家一趟,又将无人机带了回去,计划拍一下老家的风景。 原本以为穷乡僻壤的地方可以随便飞&#xf…

从新手到专家:AutoCAD 完全指南

💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 引言 AutoCAD是一款广泛用于工程设计和绘图的…

基于FPGA的9/7整数小波变换和逆变换verilog实现,包含testbench

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 9/7整数小波变换原理 4.2 逆变换过程 5.算法完整程序工程 1.算法运行效果图预览 将测试结果导入到matlab显示 2.算法运行软件版本 vivado2019.2,matlab2022a 3.部分核心程…

批量自动加好友,轻松拓展微信人脉圈子

在当今社交化的时代,拓展社交圈子已经成为许多人努力追求的目标。而微信作为中国人群中最主流的社交工具之一,更是成为人们拓展社交圈子的重要场所。在这样的背景下,有没有一种简单而高效的方式来扩大微信人脉圈子呢?答案是肯定的…

什么是智能合约

前言:在介绍智能合约的前提下,需要先介绍一下区块链 一.什么是区块链 区块链实质上是一个去中心化、分布式的可进行交易的数据库或账本,具有下列典型特征: 去中心化:简单来说,在网络上一个或多个服务器瘫…

云时空社会化商业ERP系统任意文件上传漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

046-WEB攻防-注入工具SQLMAPTamper编写指纹修改高权限操作目录架构

046-WEB攻防-注入工具&SQLMAP&Tamper编写&指纹修改&高权限操作&目录架构 #知识点: 1、SQLMAP-常规猜解&字典配置 2、SQLMAP-权限操作&文件命令 3、SQLMAP-Tamper&使用&开发 4、SQLMAP-调试指纹&风险等级 演示案例&#xf…

如何实现双向循环链表

博主主页:17_Kevin-CSDN博客 收录专栏:《数据结构》 引言 双向带头循环链表是一种常见的数据结构,它具有双向遍历的特性,并且在表头和表尾之间形成一个循环。本文将深入探讨双向带头循环链表的结构、操作和应用场景,帮…

谷歌seo推广好还是竞价排名好?

事实上seo跟sem竞价并没有任何冲突,也并没有哪个更好的说法,关键在于理解它们各自的优势与局限性,并根据你的业务,预算来配合 Seo推广的优势在于成本,只要你的网站在搜索结果获得高排名,就能有源源不断的点…

OJ_顺序存储的二叉树

题干 C实现 #define _CRT_SECURE_NO_WARNINGS #include<iostream>using namespace std;int main() {int m, n;while (1) {scanf("%d%d", &m, &n);if (m 0 && n 0) {break;}int i 1;//获取层数&#xff0c;从1开始int begin_level;//存储子…

数据中台:数字中国战略关键技术设施

目录 前言 为何要建设数据中台 数据中台建设痛点 数据中台学习资料 聚焦前沿&#xff0c;方法论体系更新 与时俱进&#xff0c;紧跟时代热点 深入6大行业&#xff0c;提炼实践精华 大咖推荐&#xff0c;数字化转型必备案头书 前言 在数字中国这一国家战略的牵引下&…

精准杜绝医疗设备漏费的智慧防线

19339904493&#xff08;康&#xff09; 医疗设备漏费管理系统&#xff0c;如同医疗设备的智慧守望者&#xff0c;时刻守护着患者的权益与医院的利益。它运用先进的人工智能算法&#xff0c;深度读取设备内部图像与项目信息&#xff0c;通过深度学习图像并分析患者的检查部位、…

招聘系统架构的设计与实现

在当今竞争激烈的人才市场中&#xff0c;有效的招聘系统对企业吸引、筛选和管理人才至关重要。本文将探讨招聘系统的架构设计与实现&#xff0c;帮助企业构建一个高效、可靠的人才招聘平台。 ## 1. 系统架构设计 ### 1.1 微服务架构 招聘系统通常采用微服务架构&#xff0c;将…

Docker制作lamp镜像并在其他机器上部署

为了方便将自己的LAMP运行环境和项目在其他机器上部署或发布&#xff0c;可以用基于Dockerhub 里的mattrayner/lamp镜像打包自己需要的镜像。 1、先选择合适的镜像文件 镜像mattrayner/lamp有多个版本&#xff0c;根据自己需要选择下载 2、镜像在首次运行时会自动下载&#x…

Python算法100例-2.9 舍罕王的失算

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序6.运行结果 1&#xff0e;问题描述 相传国际象棋是古印度舍罕王的宰相达依尔发明的。舍罕王十分喜爱象棋&#xff0c;决定让宰相自己选择何种赏赐。这位…

自学Python笔记总结(2——了解)

网络了解 网络调试助手 NetAssist.exe NetAssist.exe 使用方法请自行寻找 UDP协议 &#xff08;只能一来一回的的发消息&#xff0c;不可连续发送&#xff09; UDP 是User Datagram Protocol的简称&#xff0c; 中文名是用户数据报协议。在通信开始之前&#xff0c;不需要建…

Jrebel 使用备忘

背景 Java 开发时修改了代码如果手动中止进行然后重启的话&#xff0c;非常麻烦&#xff0c;所以需要一个热部署的插件&#xff0c;修改代码之后即时生效&#xff0c;无需重启。 之前一直用的 devtools&#xff0c;不过在一个新项目中&#xff0c;devtools 有点问题&#xff0…

组合模式(Composite Pattern)C++

上一节&#xff1a;桥接模式&#xff08;Bridge Pattern&#xff09; C 文章目录 0.理论1.目的与应用场景2.实现方式 1.实践 0.理论 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;用于将对象组合成树形结构以表示“部分-整体”的层次结…

枚举(蓝桥练习)

目录 一、枚举算法介绍 二、解空间的类型 三、循环枚举解空间 四、例题 &#xff08;一、反倍数&#xff09; &#xff08;二、特别数的和&#xff09; &#xff08;三、找到最多的数&#xff09; &#xff08;四、小蓝的漆房&#xff09; &#xff08;五、小蓝和小桥的…