【多线程进阶】synchronized 原理

news2024/11/16 23:59:46

文章目录

  • 前言
  • 1. 基本锁策略
  • 2. 加锁工作过程
    • 2.1 偏向锁
    • 2.2 轻量级锁
    • 2.3 重量级锁
  • 3. 其他的优化操作
    • 3.1 锁消除
    • 3.2 锁粗化
  • 总结


前言

在前面章节中, 提到了多线程中的锁策略, 那么我们 Java 中的锁 synchronized 背后都采取了哪些锁策略呢? 又是如何进行工作的呢? 本节我们就来谈一谈.

关注收藏, 开始学习吧🧐


1. 基本锁策略

在 Java 中, synchronized 具有以下特性(这里以 JDK 1.8 为例):

  1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁. (自适应)
  2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁. (自适应)
  3. 轻量级锁部分是基于自旋锁实现的, 重量级锁部分是基于系统的互斥锁实现的.
  4. 是非公平锁. (不会遵守先来后到. 锁释放后, 哪个线程拿到锁各凭本事)
  5. 是可重入锁. (内部会记录哪个线程拿到了锁, 并且记录引用条数)
  6. 不是读写锁.

2. 加锁工作过程

JVM 将 synchronized 锁分为 无锁, 偏向锁, 轻量级锁, 重量级锁 状态. 会根据情况, 进行依次升级.
在这里插入图片描述

2.1 偏向锁

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

  • 偏向锁不是真的 “加锁”, 只是给对象头中做一个 “偏向锁的标记”, 记录这个锁属于哪个线程.
  • 如果后续没有其他线程来竞争该锁, 那么就不用进行其他同步操作了(避免了加锁解锁的开销)
  • 如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了, 很容易识别当前申请锁的线程是不是之前记录的线程), 那就取消原来的偏向锁状态, 进入一般的轻量级锁状态.
  • 偏向锁本质上相当于 “延迟加锁” . 能不加锁就不加锁, 尽量来避免不必要的加锁开销. 但是该做的标记还是得做的, 否则无法区分何时需要真正加锁.

2.2 轻量级锁

随着其他线程进入竞争, 偏向锁状态被消除, 进入轻量级锁状态(自适应的自旋锁). 此处的轻量级锁就是通过 CAS(Compare And Swap) 来实现. CAS 就是字面意思比较并交换, 之后会有章节来讲 CAS 是什么.

  • 通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
  • 如果更新成功, 则认为加锁成功
  • 如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU).

自旋操作是一直让 CPU 空转, 比较浪费 CPU 资源. 但此处的自旋并不会一直持续进行, 而是达到一定的时间/重试次数, 就不再自旋了. 就会升级为重量级锁, 也就是所谓的 “自适应”.

2.3 重量级锁

如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会膨胀为重量级锁. 此处的重量级锁就是指用到内核提供的 mutex .

  • 执行加锁操作, 先进入内核态.
  • 在内核态判定当前锁是否已经被占用
  • 如果该锁没有占用, 则加锁成功, 并切换回用户态.
  • 如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.
  • 经历了一系列的沧海桑田, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒这个线程, 尝试重新获取锁.

3. 其他的优化操作

3.1 锁消除

有些应用程序的代码中, 用到了 synchronized, 但其实没有在多线程环境下. (例如 StringBuffer)

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");

此时每个 append 的调用都会涉及加锁和解锁. 但如果只是在单线程中执行这个代码, 那么这些加锁解锁操作是没有必要的, 白白浪费了一些资源开销.

而 JVM + 编译器, 会智能的判定, 当前的代码, 是否有必要进行加锁. 在其认为没有必要加锁的情况下, 程序员写了加锁, 就会在编译时把加锁操作自动删除掉. 当然, 在进行优化时, 是会保证优化前后逻辑是一致的.

3.2 锁粗化

一段逻辑中如果出现多次加锁解锁, 编译器 + JVM 会自动进行锁的粗化.
在这里插入图片描述

关于锁的粒度
在加锁操作中包含的要执行的代码越多, 我们就认为锁的粒度越大.
在这里插入图片描述
实际开发过程中, 使用细粒度锁, 是期望释放锁的时候其他线程能使用锁.

但是实际上可能并没有其他线程来抢占这个锁. 这种情况 JVM 就会自动把锁粗化, 避免频繁申请释放锁.


总结

✨ 本文主要讲解了 Java 中 synchronized 锁的一些原理, 是如何进行加锁的, 加锁工程又是怎样的, 以及一些内部的优化操作.
✨ 想了解更多的多线程知识, 可以收藏一下本人的多线程学习专栏, 里面会持续更新本人的学习记录, 跟随我一起不断学习.
✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

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

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

相关文章

第三课 哈希表、集合、映射

文章目录 第三课 哈希表、集合、映射lc1.两数之和--简单题目描述代码展示 lc30.串联所有单词的子串--困难题目描述代码展示 lc49.字母异位分组--中等题目描述代码展示 lc874.模拟行走机器人--中等题目描述代码展示 lc146.LRU缓存--中等题目描述相关补充思路讲解代码展示图示理解…

提升您的 Go 应用性能的 6 种方法

优化您的 Go 应用程序 1. 如果您的应用程序在 Kubernetes 中运行,请自动设置 GOMAXPROCS 以匹配 Linux 容器的 CPU 配额 Go 调度器 可以具有与运行设备的核心数量一样多的线程。由于我们的应用程序在 Kubernetes 环境中的节点上运行,当我们的 Go 应用程…

美国各流域边界下载,并利用arcgis提取与处理

一、边界数据的下载 一般使用最普遍的流域边界数据是从HydroSHEDS官网下载: HydroBASINS代表一系列矢量多边形图层,以全球尺度呈现次级流域边界。该产品的目标是提供一种无缝的全球覆盖,其中包含了不同尺度(从数十到数百万平方千米&#xf…

Docker 配置基础优化

Author:rab 为什么要优化? 你有没有发现,Docker 作为线上环境使用时,Docker 日志驱动程序的日志、存储驱动数据都比较大(尤其是在你容器需要增删比较频繁的时候),动不动就好几百 G 的大小&…

P3-Python学习当中的两大法宝函数

P3-Python学习当中的两大法宝函数 实战操作 打开pycharm,在命令行当中先检测是否是在envs当中的pytorch环境里面,或者导入torch包是否成功 dir(torch)//展示torch以下的分隔的工具包证明torch目录以下有cuda包 dir(torch.cuda.is_available())//可以展示…

Springboot学生成绩管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 学生成绩管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统 具有完整的源代码和数据库&…

golang gin——controller 模型绑定与参数校验

controller 模型绑定与参数校验 gin框架提供了多种方法可以将请求体的内容绑定到对应struct上,并且提供了一些预置的参数校验 绑定方法 根据数据源和类型的不同,gin提供了不同的绑定方法 Bind, shouldBind: 从form表单中去绑定对象BindJSON, shouldB…

【MVC】C# MVC基础知识点、原理以及容器和管道

给自己一个目标,然后坚持一段时间,总会有收获和感悟! 国庆假期马上结束,闲暇时间,重温一遍C#关于MVC的技术,控制器、视图、模型,知识点和原理,小伙伴们还记得吗 目录 一、MVC知识点1…

纸质书籍OCR方案大揭秘,快来看看有哪些神奇的黑科技

随着数字化时代的来临,纸质书籍逐渐被电子书所替代。在将纸质书籍转换为电子格式的过程中,扫描电子书目录并进行文字识别(OCR,Optical Character Recognition)成为了一项重要的工作。OCR技术能够将纸质书籍中的文字内容…

如何使用 Overleaf 编写 LaTeX 文档

如何使用 Overleaf 编写 LaTeX 文档 😇博主简介:我是一名正在攻读研究生学位的人工智能专业学生,我可以为计算机、人工智能相关本科生和研究生提供排忧解惑的服务。如果您有任何问题或困惑,欢迎随时来交流哦!&#x1f…

Firefly-LLaMA2-Chinese - 开源中文LLaMA2大模型

文章目录 关于模型列表 & 数据列表训练细节增量预训练 & 指令微调数据格式 & 数据处理逻辑增量预训练指令微调模型推理权重合并模型推理部署关于 github : https://github.com/yangjianxin1/Firefly-LLaMA2-Chinese本项目与Firefly一脉相承,专注于低资源增量预训练…

模糊搜索利器:Python的thefuzz模块详解

文章目录 thefuzz模块简介thefuzz模块的参数和方法使用thefuzz实现模糊搜索在Python中,thefuzz模块是一个用于实现模糊搜索的强大工具。它可以帮助我们在处理字符串时,快速找到相似的匹配项。本文将详细介绍thefuzz模块的功能和用法,并结合代码示例演示如何实现模糊搜索。 t…

有自动交易股票的软件么,怎么实现全自动交易?

随着技术的发展,我们经常会在看到一些关于自动交易股票软件的宣传。那么,这些软件是否真的存在?如何实现全自动交易呢? 股票量化程序化自动交易接口 一、自动交易股票软件存在吗? 答案是有,部分券商已经对…

Python数据容器——集合的相关操作

作者:Insist-- 个人主页:insist--个人主页 本文专栏:Python专栏 专栏介绍:本专栏为免费专栏,并且会持续更新python基础知识,欢迎各位订阅关注。 目录 一、理解集合 1. 集合是什么? 2. 为什么…

typora + picgo + 对象存储 OSS

文章目录 一、安装软件二、使用阿里云 oss 存储图片三、picgo 设置四、typora 设置自动上传 一、安装软件 Typora1.3.8 (安装即破解) picgo 2.3.0 安装 阿里云盘(软件安装包): https://www.aliyundrive.com/s/saQoS…

Windows10实用的12个快捷组合键

Windows10实用的12个快捷组合键 1、网页多标签切换 CTRL TAB 2、恢复不小心关闭的标签页 CTRLSHIFT T 3、新建标签页 CTRL T 4、高亮选择地址栏 ALT D 5、打开设置 WIN I 6、打开任务管理器 CTRLSHIFT ESC 7、打开文件资源管理器 WIN E 8、黑屏或屏幕卡顿无响应&#x…

python实验(超详细)

目录 实验一 python编程基础实验二 python序列、字符串处理实验三 函数及python类的定义与使用实验四 python综合应用 实验一 python编程基础 在交互式环境中打印“Hello world”字符串。记录操作过程。 略 创建脚本helloworld.py,在命令符提示环境中执行程序&…

【Oracle】Oracle系列十八--Oracle RAC

文章目录 往期回顾前言1. Oracle RAC介绍1.1 基本概念1.2 Oracle RAC应用场景1.3 Oracle RAC的优缺点 2. Oracle RAC架构3. Oracle RAC 的安装 往期回顾 【Oracle】Oracle系列之一–Oracle数据类型 【Oracle】Oracle系列之二–Oracle数据字典 【Oracle】Oracle系列之三–Orac…

CDN网络基础入门:CDN原理及架构

背景 互联网业务的繁荣让各类门户网站、短视频、剧集观看、在线教育等内容生态快速发展,互联网流量呈现爆发式增长,自然也面临着海量内容分发效率上的挑战,那么作为终端用户,我们获取资源的体验是否有提升呢? 答案是…

网络层·IP协议

承接前文TCP协议-CSDN博客 简介 协议头格式 网段划分(重要) 划分方法 IP地址的数量限制(背景介绍) 私有IP地址和公网IP地址(提出解决思路) NAT技术(解决方法) 路由 网络层 在复杂的网络环境中确定一个合适的路径 IP协议 主机: 配有IP地址, 可以认为就是你的电脑; 路由器:…