【Java多线程进阶】synchronized工作原理

news2024/12/23 19:02:52

 前言

本期讲解 synchronized 工作的原理以及常见的锁优化机制,相信大家在看完这篇博文后对 synchronized 工作流程有一定的理解。话不多说,让我们快速进入学习吧~

目录

1. 锁的工作流程

2. 偏向锁

3. 轻量级锁和重量级锁

3.1 轻量级锁

3.2 重量级锁

4. 常见的锁优化

4.1 锁消除

4.2 锁粗化


1. 锁的工作流程

众所周知,synchronized 关键字是用来加锁的,加锁的原因就是多个线程抢占资源导致线程执行的过程不具备原子性。

JVM 将 synchronized 加锁的过程分为四个状态分为无锁、偏向锁、轻量级锁、重量级锁。刚开始是无锁状态,加上锁后处于偏向锁状态,锁有了竞争锁升级为轻量级锁,锁的竞争更加激烈了升级为重量级锁状态。

举例说明:

有个女孩叫如花,有个男孩叫阿三,如花是个漂亮的女孩,阿三是个帅气又有钱的男孩。

阿三追求如花,如花不想确定情侣关系也不想放弃阿三,于是如花吊着阿三,此时就处于一个偏向锁状态。阿三就像锁,锁的竞争不激烈,如花有恃无恐,锁处于 偏向锁 状态。

某一天,如花发现阿三正在被其他女孩追求,如花慌了立马跟张三确定男女关系,此时就处于轻量级锁状态。锁的竞争激烈了,锁升级为 轻量级锁

随着日子一天天过去,越来越多女孩开始爱慕阿三。如花更加紧张了,生怕张三离开她,于是越来越限制张三的自由了,此时就处于重量级锁状态。锁的竞争更加激烈了,锁升级为 轻量级锁

在上述例子中,阿三为锁,如花为 JVM。JVM 通过锁的竞争程度,来决定锁的策略是什么。


2. 偏向锁

第一尝试获取锁的线程,优先处于偏向锁的状态。此时这个线程并未进行加锁操作,而是通过一个 标记 来确定这是第一次获取锁的线程。

如果代码在整个运行过程中,没有遇到其他线程来竞争锁。就不会进行加锁了。但,如果有线程进行竞争锁,此时偏向锁就会变成一把真正的锁(轻量级锁)。

偏向锁,主要体现能不加锁就不加锁这个概念,它实际上并没有加锁只是通过一个标记来确定锁于无竞争状态,等到锁有竞争情况发生了,偏向锁才会变成一把锁(轻量级锁)。


举例:

21世纪流行着这样一段关系:

有一个男孩小强和一个女孩小美,小强是一把锁,小美是一个线程。小强和小美想过着夫妻一般的生活但不去领证。此时,小美在使用这把锁的时候锁的状态为偏向锁,因为没有其他线程竞争这把锁。

某一天,小强在公司认识了一个女孩小宣,小宣是一个线程。小宣爱慕小强,于是追求他。小美不想小强被抢走,于是和小强结婚(领证)。此时,小美使用小强这把锁就变成了轻量级锁状态。最后小强只得对小宣说:“你是个好女孩,我配不上你”。


3. 轻量级锁和重量级锁

轻量级锁为了避免进入同步状态,采用了一些基于CAS操作的优化手段,但如果线程CAS操作失败并达到一定次数后,会进入自旋锁状态等待获取锁。但如果自旋等待的时间过长,就需要升级为重量级锁,这是为了让其它线程有机会抢到锁。

升级为重量级锁后,会将当前线程阻塞并进入内核态,而不再直接进入自旋锁状态等待,这样可以避免浪费CPU资源。同时,重量级锁在释放锁的时候,也需要进行内核态的操作,因此其释放锁的代价相对较高。

关于CAS相关信息在这篇博文中有详细介绍:【Java多线程进阶】CAS机制_一只爱打拳的程序猿的博客-CSDN博客


3.1 轻量级锁

通过上文讲解,我们了解到随着其他线程竞争锁,锁由偏向锁状态升级为轻量级锁状态。轻量级锁状态,实际上就是自适应的自旋锁状态。

此处的轻量级锁,是通过 CAS 机制来实现的:

  • 通过 CAS 机制检查并且更新一块内存。
  • 如果更新成功,则加锁成功。
  • 更新失败,则认为锁被占用,继续自旋式的等待。

自旋式,就是通过一个循环来判定锁是否被占用。如果锁被占用此时会无限循环,直到锁不被占用退出循环。在此期间,自选锁一直占用着 CPU 资源,比较浪费。


3.2 重量级锁

如果锁竞争愈发激烈,自旋锁不能快速获取到锁的状态,就会升级为重量级锁。此时的重量级锁会引申到内核态与用户态。

轻量级锁与重量级锁在这篇文章中有详细介绍:【Java多线程进阶】常见的锁策略_一只爱打拳的程序猿的博客-CSDN博客


4. 常见的锁优化

常见的锁优化有两种:锁消除于锁粗化。请看下方讲解。


4.1 锁消除

锁消除是一种编译器优化机制,当代码块被 synchronized 锁住时。如果该代码块只被某一线程独占则 synchronized 就被编译器消除了,因为编译器会检查并认为该代码块并不需要加锁,也就是我们所说的锁被消除了。

当然,多个线程使用多把锁时,只要互不干扰各自使用各自的锁资源,这种情况锁也会被消除。

锁消除是一种优化技术,它可以减少不必要的锁操作对性能的影响,提高程序的执行效率,节省系统消耗的资源。


4.2 锁粗化

谈到锁粗化,我们会联想到一个“粒度感”,代码越多粒度越粗,代码越少粒度越细。在写代码的过程中,我们很难兼容到要保证代码少又要保证代码好。

比如在某个场景下,我们频繁的使用 加锁/解锁 操作,编译器会通过优化手段将这些频繁的 加锁解锁 进行粗化,这样就能大大减小系统开销,也就是我们所说的锁粗化。

举例说明:

在公司上班,老板上午安排了一个任务给我,下午安排了个任务给我,晚上又安排了一个任务给我,要求我明天晚上之前要完成。

如果我今天下午完成第一个任务打电话给老板并汇报工作,明天上午完成了第二个任务再打电话给老板,明天晚上完成了第三个任务又打电话给老板。

老板心里肯定想,这人烦不烦一起给我不就得了。(当然,在任务不紧急的情况下)

如果我一次性汇报三个任务,此时就大大减少了老板接电话(上锁)挂电话(解锁)的开销。


synchronized工作原理是什么?

synchronized 刚开始是无锁的状态,当 synchronized 所修饰的资源被线程独占后就升级为偏向锁状态,当 synchronized 被多个线程竞争后就升级为轻量级锁,锁的竞争越来越激烈并且锁释放得很慢此时就会升级为重量级锁状态。


什么是偏向锁、轻量级锁、重量级锁?

偏向锁:第一个使用到锁的线程,此时并未进行锁操作,编译器会使用一个标识来确定这个锁只被一个线程使用。

轻量级锁:当锁被多个线程竞争了,此时锁会从偏向锁升级为轻量级锁,轻量级锁会通过 CAS 机制即自旋操作,来无限循环尝试获取锁直到获取到锁为止。因此,在获取到锁之前会一直占用CPU资源,容易浪费资源。

重量级锁:当锁竞争激烈并且锁资源释放过慢,此时锁会中轻量级锁升级为重量级锁,重量级锁会跟随系统的调度不再进行自旋等待,直到锁释放了,再参与锁的竞争,大大减少了系统资源的浪费。


🧑‍💻作者:一只爱打拳的程序猿,Java领域新星创作者,CSDN、阿里云社区优质创作者。

📒博客主页:这是博主的主页 

🗃️文章收录于:Java多线程编程 

🗂️JavaSE的学习:JavaSE 

🗂️Java数据结构:数据结构与算法 

 

本篇博文到这里就结束了,感谢点赞,评论,收藏,关注~

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

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

相关文章

Kubernetes基本存储

Kubernetes基本存储 容器的生命周期可能很短,会被频繁地创建和销毁,容器销毁时,保存在容器中的数据也会被清除。为了持久化保存容器中数据,引入Volume概念。 Volume时Pod中多个容器共同访问的共享目录,它被定义在Pod中…

“碳”寻青蓝锦色,锦江酒店(中国区)用行动点亮酒店可持续发展

第52个世界环境日之际,为响应“减塑捡塑”号召,锦江酒店(中国区)以“‘碳’寻青蓝锦色”为主题,在6月5日至6月11日期间,开启第二届“绿色生活创益周”,通过线上线下联动,倡导时尚低碳…

2023智源大会议程公开丨类脑计算论坛

6月9日,2023北京智源大会,将邀请这一领域的探索者、实践者、以及关心智能科学的每个人,共同拉开未来舞台的帷幕,你准备好了吗?与会知名嘉宾包括,图灵奖得主Yann LeCun、图灵奖得主Geoffrey Hinton、OpenAI创…

Mocha AE:Clip 模块

Clip(剪辑)模块主要用于对素材或遮罩文件的格式进行查看或设置,包括视频格式、时间码格式、色彩空间等,还可以进行裁剪。 General 常规 Input 输入 当前图层素材。 Matte for Layer n 图层 n 的遮罩 Name 名称 显示素材的名称。 …

通信大史记:互联网的起源故事

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 文案 / 朱峰 产品统筹 / bobo 这是一期“两年更”的节目,通信大史记录完第一期后,因为资料准备和主播时间的关系一直没有后续更新。今天,我们…

nodejs的path模块

path路径模块 path模块是Node.js官方提供的,用来处理路径的模块。提供一系列的方法和属性,用来满足用户对路径的处理需求。 例如: 如果在js代码中,使用path模块来处理路径,需要先导入 const pathrequire(path)常用的…

chatgpt赋能python:Python如何调成白色的SEO文章

Python 如何调成白色的 SEO 文章 介绍 Python 是一种流行的编程语言,在数据分析、人工智能、Web 开发以及其他许多领域都有广泛的应用。然而,很少有人会把 Python 与 SEO 联系起来。 事实上,Python 是一个强大的工具,可以帮助 …

软件工程师,学会封装不香么

什么是封装 从面向对象编程的角度来说,封装是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与…

rk3568 TF卡启动

rk3568 SD卡启动 SD卡启动系统,它可以让rk3568在没有硬盘或其他存储设备的情况下启动和运行操作系统。这使得rk3568变得与树梅派一样灵活切换系统,与此同时进行故障排查和修复,而不需要拆卸设备或者使用专业的烧录工具。SD卡启动还可以方便地…

音视频同步的方法:深入探索基于FFmpeg的音视频同步策略

音视频同步艺术:深入探索基于FFmpeg的同步策略 (一)音视频同步的基本概念与重要性(Basic Concepts and Importance of Audio-Video Synchronization)1.1 音视频同步的定义与影响(Definition and Impact of …

【SQL】Oracle数据库实现远程访问

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle,是甲骨文公司的一款关系…

【Python入门】Python循环语句(for循环的基础语法)

前言 Python循环语句 1. for循环的基础语法1.1 for循环1.2 程序中的for循环1.3 for循环语句1.4 for循环注意点1.5 总结1.6 练习案例:数一数有几个a 2. range语句2.1 range语句讲解2.2 for循环遍历range序列2.3 总结2.4 练习案例:有几个偶数 3. 变量作用域…

RFID软件:简介、功能和应用范围

在当今快节奏的商业环境中,RFID(射频识别)技术已经成为物流、供应链和库存管理等领域中不可或缺的工具。本文将向您介绍RFID软件的基本知识,探讨其功能和广泛应用的范围。 第一部分:RFID软件简介 RFID软件是一种应用…

【开源项目】SofaBoot实现Spring Bean 异步初始化的源码拆解

使用场景 在实际使用 Spring/Spring Boot 开发中,一些 Bean 在初始化过程中执行准备操作,如拉取远程配置、初始化数据源等等。在应用启动期间,这些 Bean 会增加 Spring 上下文刷新时间,导致应用启动耗时变长。 Demo展示 Spring…

苹果 Apple 发布的 AR 头显 Vision Pro 介绍

苹果今天凌晨的发布会,隆重推出了用了8 年时间研发的AR(增强现实)头戴显示器 Vision Pro。作为苹果 AR系列的最新成员,为用户带来了前所未有的沉浸式增强现实体验。 硬件 12个摄像头 ,包括苹果首个 3D 相机&#xff0c…

【容器云架构】Calico 组件架构

Calico 组件 下图显示了 Kubernetes 的必需和可选 Calico 组件,具有网络和网络策略的本地部署。 Calico 组件 Calico API serverFelixBIRDconfdDikastesCNI pluginDatastore pluginIPAM pluginkube-controllersTyphacalicoctl 云编排器的插件 Plugins for cloud orc…

【vulnhub靶场】node 1

文章目录 前言开启靶机信息收集二层发现三层信息收集 攻击利用web信息收集权限提升后渗透 前言 描述:Node是一个中等级别的boot2root挑战,最初是为HackTheBox创建的。有两个标志可供查找(用户和根标志)和多种不同的技术可供使用。…

IDEA启动图片更改替换(2021.1/2022及其之后的版本)

目录 先说2022.1及其之后的版本: 2022.1之前的版本: 2022其他版本修改方法 最近一直在整理接口数据,盯屏幕太久了,然后打开IDEA突然感觉这个启动页面好刺眼,正好整理工作做完了,中午有空就找了下方法,发现了不少坑,…

项目管理中,如何减少项目风险?

我们公司,有一个项目已经做了一年多了,并且与客户进行了多次沟通,项目需求变更,范围扩大等,项目一直不能完成,客户生气,领导一直催,决定换一个项目经理把,领导让一个同事…

《vue 实践之 three.js 学习》

目录 three.js 学习包安装导包基础API学习Three.js 三要素【图文展示】 透视相机three.js 渲染器 之 WebGLRendererWebGLRenderer 实例化 three.js 学习 个人博客地址: 包安装 "three": "^0.153.0"命令:npm install --save three –…