JavaEE-常见的锁策略和synchronized的锁机制
目录
- 常见的锁策略
- 乐观锁和悲观锁
- 轻量级锁和重量级锁
- 自旋锁和挂起等待锁
- 普通互斥锁和读写锁
- 公平锁和非公平锁
- 可重入锁和不可重入锁
- synchronized的锁机制
- synchronized特性
- 锁升级/锁膨胀
- 锁消除
- 锁粗化
常见的锁策略
乐观锁和悲观锁
乐观锁和悲观锁主要是看主要是锁竞争的激烈程度.
- 乐观锁预测锁竞争不是很激烈, 做的准备工作相对更少, 开销更小, 效率更高.
- 悲观锁预测锁竞争会很激烈, 做的准备工作相对更多, 开销更大, 效率更低.
乐观锁一般应用在线程的冲突比较少, 也就是说读操作比较多, 写操作比较少; 而悲观锁则相反, 一般应用在线程冲突比较多, 写操作比较多的情况下.
轻量级锁和重量级锁
轻量级锁和重量级锁看的是锁操作的开销大不大.
- 重量级锁: 加锁解锁的开销比较的大, 需要在内核态中进行完成, 多数情况下悲观锁是一个重量级锁, 但并不绝对.
- 轻量级锁: 它的开销比较小, 在用户态中完成就行, 多数情况下乐观锁是一个轻量级锁, 但并不绝对.
轻量级锁一般都是通过版本号机制或CAS算法进行实现的, 但对用重量级锁来说不是, 这与操作系统的内核有关, cpu一般会提供一些特殊指令, 操作系统会对这些指令进行封装一层, 提供一个mutex(互斥量), 在Linux种就会提供一个这样的接口供用户进行加锁解锁; 一般来说, 如果锁是通过调用mutex来进行实现的, 那么这个锁就是一个重量级锁. 自旋锁和挂起等待锁
- 自旋锁: 是一种典型的轻量级锁, 在线程获取不到锁的情况下, 不会立刻放弃CPU, 而是会一直快速频繁进行获取, 直到获取到锁; 这种策略的优势在于节省线程调度的开销并且更能及时的获取到锁, 缺点就是更加浪费cpu资源.
- 挂起等待锁: 是一种典型的重量级锁, 线程在获取不到锁的情况下会堵塞等待(放弃CPU,进入等待队列), 然后等到锁被释放的时候再有操作系统调度.
普通互斥锁和读写锁
Java中synchronized的锁就是一个普通的互斥锁, 只涉及两个操作:
- 加锁
- 解锁
多线程针对同一个变量并发读, 这个时候没有线程安全问题的, 也不需要加锁控制, 对于读写锁来说, 分成了三个操作:
加读锁:如果代码只进行了读操作,就加读锁 加写锁:如果代码进行了修改操作,就加写锁 解锁: 针对读锁和读锁之间,是不存在互斥关系的读锁和读锁之间是没有互斥的, 读锁和写锁之间, 写锁和写锁之间, 才需要互斥
在java中有读写锁的标准类, 位于java.util.concurrent.locks.ReentrantReadWriteLock, 其中ReentrantReadWriteLock.ReadLock为读锁,ReentrantReadWriteLock.WriteLock为写锁.公平锁和非公平锁
- 公平锁: 多个线程在等待一把锁的时候, 遵循先来后到原则, 谁是先来的, 谁就先获得这把锁.
- 非公平锁: 多个线程等待同一把锁, 不遵守先来后到原则, 每个人等待线程获取锁的概率是均等的.
操作系统中原生的锁都是 “非公平锁”, 操作系统中的针对加锁的控制, 是依赖于线程调度顺序的, 这个调度顺序是随机的, 不会考虑到这个线程等待锁多久了, 如果想要实现公平锁, 就得在这个基础上加额外的数据结构(比如引入一个队列), 来记录线程的先后顺序.
可重入锁和不可重入锁
- 可重入锁: 一个线程针对同一把锁连续加锁两次,不会出现死锁
- 不可重入锁: 一个线程针对同一把锁连续加锁两次,会出现死锁
synchronized的锁机制
synchronized特性
Synchronized具有如下特性:既是乐观锁也是悲观锁, 当锁竞争较小时它就是乐观锁(默认), 锁竞争较大时它就是悲观锁. 是普通互斥锁。 既是轻量级锁(默认)也是重量级锁, 根据锁竞争激烈程度自适应. 轻量级锁部分基于自旋锁实现, 重量级锁部分基于挂起等待锁实现. 是非公平锁. 是可重入锁.锁升级/锁膨胀
JVM 将 synchronized 锁分为 无锁, 偏向锁, 轻量级锁, 重量级锁 状态; 会根据情况, 进行依次升级.

-
当没有线程加锁的时候, 此时为无锁状态.
-
当首个线程进行加锁的时候, 此时进入偏向锁的状态, 偏向锁不是真的加锁, 而是在对象头做个标记(这个过程是非常轻量的).
偏向锁并不是真的加锁, 只是做了一个标记, 这样带来的好处就是, 后续如果没人竞争的时候, 就一直不去确立关系(节省了确立关系/分手的开销), 如果没有其他的线程来竞争这个锁, 就不必真的加锁(节省了加锁解锁的开销), 如果在执行代码过程中, 并没有其他线程来尝试加锁, 那么在执行完synchronized之后, 取消偏向锁即可.
-
当有其他线程进行加锁, 导致产生了锁竞争时, 此时进入轻量级锁状态(迅速的把偏向锁升级成真正的加锁状态).
此处的轻量级锁是通过 CAS 来实现的, 如果其他的线程很快的释放锁, 那么我们的自旋锁是非常合适的, 但是如果其他线程长时间占用锁, 自旋锁就不太合适了, 自旋操作是一直让 CPU 空转, 比较浪费 CPU 资源, 因此此处的自旋不会一直持续进行, 而是达到一定的时间/重试次数, 就不再自旋了, 也就是所谓的 “自适应”.
-
如果竞争进一步加剧, 进入重量级锁状态(挂起等待锁).
重量级锁是基于操作系统原生的一组API(mutex)来进行加锁了, 当我们自旋不能快速获取到锁时, 锁竞争加剧, 就会升级为重量级锁, 我们的线程就会被放到阻塞队列中, 暂时不参与CPU调度, 当锁被释放了之后, 线程才有机会被调度, 从而有机会获取到锁, 一旦线程被切换出cpu, 这就是比较低效的事情了.
锁消除
锁消除是编译器的智能判定, 有些代码, 编译器认为没有加锁的必要, 就会自动把你加的锁自动去除, 比如字符串相关的线程安全类
StringBuffer, 这个类中的关键方法都带有synchronized, 但是当我们在单线程环境下使用StringBuffer,不会涉及到线程安全问题, 此时编译器就会直接把这些加锁操作去除了.锁粗化
锁粗化就是将
synchronized的加锁代码块范围增大, 加锁的代码块中的代码越多, 锁的粒度就越粗, 否则锁的粒度就越细.通常情况下, 认为锁的粒度细一点比较好, 加锁的部分的代码, 是不能并发执行的, 锁的粒度越细, 能并发的代码就越多, 反之就越少.
但是有些情况下, 锁的粒度粗一些反而更好, 如果我们两次加锁解锁的时间间隙非常小, 分开加锁会造成额外的资源开销, 而且中间间隙很小, 就算并发效果也不是很明显, 这种情况下不如直接一把大锁搞定.
-
相关文章:
JavaEE-常见的锁策略和synchronized的锁机制
目录常见的锁策略乐观锁和悲观锁轻量级锁和重量级锁自旋锁和挂起等待锁普通互斥锁和读写锁公平锁和非公平锁可重入锁和不可重入锁synchronized的锁机制synchronized特性锁升级/锁膨胀锁消除锁粗化常见的锁策略 乐观锁和悲观锁 乐观锁和悲观锁主要是看主要是锁竞争的激烈程度.…...
信息化,数字化,智能化是三种不同的概念吗?
前两年流行“信息化”,网上铺天盖地都是关于“信息化”的文章,这两年开始流行起“数字化”,于是铺天盖地都是“数字化”的文章。(这一点从数字化和信息化这两个关键词热度趋势就可以看出来)。 但点开那些文章仔细看看…...
【华为OD机试 2023最新 】 匿名信(C++ 100%)
题目描述 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节,且不暴露自己,于是将报刊上的字减下来,剪拼成匿名信。 现在又一名举报人,希望借鉴这种手段,使用英文报刊完成举报操作。 但为了增加文章的混淆度,只需满足每个单词中字母数量一致即可,不关注每个…...
硬件语言Verilog HDL牛客刷题day05 时序逻辑部分
1.VL29 信号发生器 1.题目: 题目描述: 请编写一个信号发生器模块,根据波形选择信号wave_choise发出相应的波形:wave_choice0时,发出方波信号;wave_choice1时,发出锯齿波信号;wave…...
Ajax 入门
前端技术:在浏览器中执行的程序都是前端技术。如 html、css、js 等 后端技术:在服务器中执行的长须,使用 Java 等语言开发的后端程序。servlet,jsp,jdbc,mysql,tomacat 等 全局刷新 使用表单…...
半导体器件基础06:发光二极管
说在开头:关于玻尔原子模型(1) 卢瑟福的模型面临着与经典电磁波理论的矛盾,按照经典电磁波理论,卢瑟福的原子不可能稳定存在超过1秒钟。玻尔面临着选择:要么放弃卢瑟福模型,要么放弃麦克斯韦伟…...
AutoCV第二课:Python基础
目录Python基础前言1.流程控制1.1 条件语句1.2 循环语句1.2.1 while循环语句1.2.2 for循环语句1.3 作业1.4 拓展-try except语法2.函数2.1 函数定义2.2 函数的参数2.2.1 位置参数2.2.2 命名参数2.2.3 默认参数2.2.4 可变参数2.2.5 参数展开2.3 递归函数2.3.1 递归函数定义2.3.2…...
LeetCode算法 打家劫舍 和 打家劫舍II C++
目录题目 打家劫舍参考答案题目 打家劫舍II参考答案题目 打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯…...
蓝桥杯刷题冲刺 | 倒计时10天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.有边数限制的最短路2.九进制转十进制1.有边数限制的最短路 题目 链接: 853. 有边数…...
个人练习-Leetcode-剑指 Offer II 109. 开密码锁
题目链接:https://leetcode.cn/problems/zlDJc7/ 题目大意:给出一个四位数字的密码锁,初始状态是0000,目标是targer。每一次转动只能让一个位的轮盘转动一下(0往后转是9)。有一个vector<string> dea…...
四个常见的Linux面试问题
四个常见的Linux面试问题。 刚毕业要找工作了,只要是你找工作就会有面试这个环节,那么在面试环节中,有哪些注意事项值得我的关注呢?特别是专业技术岗位,这样的岗位询问一般都是在职的工程师,如何在面试环节…...
15、接口(C#)
15.1 什么是接口 接口是指定一组函数成员而不实现它们的引用类型。所以只能类和结构实现接口。 15.2 声明接口 接口声明不能包含以下成员 数据成员静态成员 接口声明只能包含以下类型的费静态成员函数声明: 方法事件索引器属性 这些函数成员的声明不能包含任何实…...
C++中常见的容器类使用方法举例(vector、deque、map、set)
cpp中常见的容器类有vector、list、deque、map、set、unordered_map和unordered_set。 下面将举例直接说明各个容器的使用方法。 文章目录综合示例1. vector:动态数组,支持随机访问2. list:双向链表,支持双向遍历和插入删除3. de…...
什么是强缓存和协商缓存
什么是缓存 浏览器缓存就是把一个已经请求过的Web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中。缓存会根据进来的请求保存输出内容的副本。当下一个请求来到的时候,如果是相同的URL&#…...
算法刷题之堆
1. heapq 堆 Python 中只有最小堆: import heapqa [] heapq.heappush(a, 3) # 添加元素 heapq.heappush(a, 2) heapq.heappush(a, 1) while len(a): # 判断堆的长度print(heapq.heappop(a)) # 弹出堆顶元素# 将列表转换为最小堆 nums [2, 3, 1, 4, 5, 6] hea…...
javaweb导师选择系统
本文以JSP为开发技术,实现了一个导师选择系统。导师选择系统分为三大模块,包括管理员:学员信息管理、导师信息管理、导师选择管理、导师分布图、公告信息管理、系统管理,学生:个人资料管理、导师选择管理、导师分布图管…...
LeetCode150 逆波兰表达式求值
题目: 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。 注意: 有效的算符为 ‘’、‘-’、‘*’ 和 ‘/’ 。每个操作数(运算对象)都可以…...
【Node.js】项目开发实战(中)
开发用户的注册和登录接口步骤1,打开MySQL Workbench,打开自己的数据库进入创建用户信息表新建 ev_users表安装并配置mysql模块安装mysql模块新建db文件夹下index.js,导入并配置mysql模块安装bcryptjs对密码进行加密处理新建/router_handler/user.js中&a…...
记录一次 New Bing 英语陪练
记录一次 New Bing 英语陪练 Now I start to speak english to chat with you . Help me find the mistake in my word and help me improve my english I’m glad you want to practice your English with me. I can help you find the mistakes in your words and help you i…...
【Python】照片居然能变素描?不会画画但是咱会代码
文章目录前言一、准备二、下载预训练模型总结前言 Photo-Sketching 一个能将照片的轮廓识别出来并将其转化为“速写”型图像的开源模块。 比如,这只小狗: 经过模型的转化,会变成卡通版的小狗: 非常秀,这很人工智能…...
利用Google可编程搜索引擎API实现免费高效的Python搜索自动化
1. 项目概述:一个被低估的搜索利器 如果你经常需要从Google上批量、自动化地获取搜索结果,并且对搜索结果的质量、速度和稳定性有要求,那你一定遇到过官方API的种种限制,或者对第三方付费服务望而却步。今天要聊的这个项目 chhan…...
南京彩钢瓦屋面防水供应商
在南京,彩钢瓦屋面广泛应用于各类建筑,然而其防水问题一直是困扰众多业主的难题。选择一家靠谱的彩钢瓦屋面防水供应商至关重要。今天就为大家详细介绍雨中行修缮工程有限公司,同时也对比其他一些大厂,看看雨中行修缮为何能在市场…...
Atlas机器人:人形设计、液压驱动与救灾场景下的技术权衡
1. 项目概述:Atlas,一个充满争议的工程里程碑2013年,当波士顿动力公司为DARPA(美国国防高级研究计划局)打造的Atlas机器人首次公开亮相时,它在工程技术社区引发的震动,远不止于其令人惊叹的行走…...
数据分析实习面试准备全攻略:专业知识+项目深挖+行为面试,职卓科技的面试辅导体系
摘要数据分析实习面试通常包含三大模块:专业知识考察(SQL、Python、统计学基础)、项目深挖(业务理解、技术选择、问题解决)、行为面试(团队协作、学习能力、职业规划)。很多学员在面试中表现不佳…...
【2026社工】初级社会工作者历年真题及答案PDF电子版(2010-2025年)
2026年初级社会工作者职业水平考试安排 考试时间: 2026年5月23日 考试科目与形式 科目名称考试形式社会工作实务闭卷笔试社会工作综合能力闭卷笔试 备考资源说明 提供2010-2025年完整历年真题及解析,覆盖全部考试科目,具体功能如下&#…...
C语言-指针二
一. 指针的操作int main() {int a 10 , b 20, c 30;int *p NULL, *q NULL;p &a;//对指针变量p本身进行修改b *p;//*p为右值表示对变量a的读取*p 60;//*p为左值表示通过指向的内存空间对变量a的写入p &c;//p指向的内存空间发生变化b *p;//对c的读取操作*p 70…...
告别手动改包!用Fiddler的Free HTTP插件实现自动化测试(附实战配置)
构建高效HTTP流量自动化测试体系:Fiddler Free HTTP插件深度实践 在持续交付和DevOps成为主流的今天,自动化测试已成为保障软件质量不可或缺的一环。然而,许多团队在接口测试环节仍面临重复劳动:每次测试都需要手动修改请求参数、…...
从数据模型到领域驱动设计:数据库抽象与微服务实践的演进
在软件开发的漫长历史中,如何有效地对现实世界进行建模,始终是核心挑战之一。从早期的层次数据库到当今的微服务架构,数据模型作为连接业务需求与技术实现的桥梁,经历了深刻的演变。本文基于对概念数据模型、基本数据模型和面向对象模型的系统探讨,进一步延伸到领域驱动设…...
基于VitePress构建开源AI智能体框架深度中文文档站实战指南
1. 项目概述:一个为AI智能体框架量身打造的中文文档站如果你正在寻找一个能帮你把Claude、GPT这些大模型快速接入到微信、Telegram、飞书等聊天软件的开源框架,那你大概率会接触到OpenClaw(原名ClawdBot)。但当你兴冲冲地打开官方…...
数字时代的计划性抹杀:从强制升级到生态锁定的技术围剿
1. 数字时代的“计划性报废”:从凯迪拉克到小电驴的隐喻 前几天,我在网上申请一张信用卡,过程堪称一场荒诞剧。银行明明通过邮件联系我,也知道我的账号密码,甚至在我通过了“我不是机器人”的图片验证后,却…...
