synchronized原理
目录
一、基本特点
二、加锁过程
2.1、偏向锁
2.2、轻量级锁
2.3、重量级锁
三、其它的优化操作
3.1、锁消除
3.2、锁粗化
一、基本特点
synchronized有以下特性:
- 开始是乐观锁,如果锁冲突频繁,就转换为悲观锁。
- 开始是轻量级锁,如果锁被持有的时间较长,就转换为重量级锁。
- 实现轻量级锁的时候大概率用到的自旋锁策略。
- 是一种不公平锁。
- 是一种可重入锁。
- 不是读写锁。
二、加锁过程
JVM会将synchronizde锁分为无锁,偏向锁,轻量级锁,重量级锁状态。根据锁的激烈程度,自动进行锁升级。
举个栗子:
1、我们在学校每天早上去图书馆学习,‘坤坤’已经在图书馆学习时长两年半,所以坤坤每天都要起一个大早去学习,他真的很努力,所以他到了图书馆基本上没有人,坤坤可以随便坐。
2、过了一个小时,有真爱粉来图书馆找咯咯一起学习,真爱粉就把书本放在桌子上,标志着这个地方有人了,给自己占了个位置,其他人不准用。
3、 随着真爱粉越来越多,学习的人也越来越多,图书馆也就慢慢有了竞争,于是有的同学的书本就会被放在一边,自己的位置被别人占了,真爱粉回来之后发现座位被占了,周围也满了,她就站在原地一直等,相当于自旋状态,可以在第一时间发现空余作为,效率比较高。
4、听说咯咯每天都去图书馆学习,小黑子门也急了,他们也要去图书占位,于是图书馆的座位竞争越来越激烈,高峰时期就要排队(阻塞队列),阻塞队列也就越来越长,每个人都要检查锁,如果没有可用的锁就要去排队,对于synchronized来说,相当于是重量级锁,会调用内核态的加锁指令,来完成获取锁操作。
2.1、偏向锁
第一个尝试加锁的线程,会优先进入偏向锁。
偏向锁不是真的”加锁“,而是给对象头加了一个”偏向锁标记“,记录这个锁属于哪个线程。
如果后续没有其它线程来竞争该锁,那么就不用进行其它同步操作了(避免了加锁解锁的资源开销)如果后续有其它线程来竞争该锁,那就取消原来的偏向锁状态,进入一般的轻量级锁状态。
偏向锁的本质上相当于”延迟加锁“,能不加锁就不加锁,避免资源的浪费。
但是该做标记还是要做,否则无法区分何时真正加锁。
2.2、轻量级锁
随着其它线程进入竞争,偏向锁状态被解除,进入轻量级锁状态
此处的轻量级锁就通过CAS(自旋)来实现.
- 通过CAS检查并更新一块内存(比如null=>该线程引用)。
- 如果更新成功,则认为加锁成功。
- 如果更新失败,则认为锁被占用,继续自旋式等待锁释放(并不放弃CPU)。
自旋操作是让CPU一直空转,比较浪费资源,因此自旋状态不会一直持续进行,而是达到一定时间(重试次数),就不再自旋,也就是”自适应“。
2.3、重量级锁
如果锁竞争进一步激烈,自旋不能快速获取到锁,就会膨胀为重量级锁。
此处的重量级锁就是指内核提供的mutex.
- 执行加锁操作,先进入内核状态。
- 在内核判定当前锁是否已经被占用。
- 如果该锁没有被占用,则加锁成功,并切换回用户态。
- 如果该锁被占用,则加锁失败。此时线程进入锁的等待队列,挂起,等待被唤醒。
- 经历了一系列操作,这个锁被其它线程释放了,操作系统也想起了这个被挂起的线程,于是唤醒这个线程,尝试重新获取锁。
打印类的布局:
import org.openjdk.jol.info.ClassLayout;/*** 打印类的布局*/
public class Exe_01 {//定义变量private int count = 100;private long count1 = 200;private String hello = "";private TextExe_01 textExe_01 = new TextExe_01();public static void main(String[] args) throws InterruptedException {//创建一个对象的实例Object obj = new Object();//打印实例布局System.out.println("=====任意object对象布局,起初无锁状态");System.out.println(ClassLayout.parseInstance(obj).toPrintable());System.out.println("延迟三秒开启偏向锁");//延迟3秒开启偏向锁Thread.sleep(3000);//创建本类的实例Exe_01 monitor = new Exe_01();//打印实例布局,查看锁状态System.out.println("=====打印实例布局,注意查看锁状态为偏向锁");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());//调用hashCode后,保存hashCode的值monitor.hashCode();//观察现象System.out.println(ClassLayout.parseInstance(monitor).toPrintable());System.out.println("==============================");System.out.println("synchronized加锁");//加锁后观察锁信息synchronized (monitor) {System.out.println("第一层synchronized加锁后");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());//锁重入,观察锁信息synchronized (monitor) {System.out.println("第二层synchronized加锁后,锁重入");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());}//释放里层的锁System.out.println("释放内层锁后");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());}//释放所有锁之后System.out.println("=========释放所有锁========");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());System.out.println("==== 多个线程参与锁竞争,观察锁状态");//强制执行垃圾回收System.gc();//观察GC计数System.out.println("+++++++调用GC后查看age的值");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());//打印类布局,调用不同的方法查看System.out.println("+++++查看类布局");System.out.println(ClassLayout.parseClass(Exe_01.class).toPrintable());//打印类对象布局System.out.println("+++++查看类对象布局");System.out.println(ClassLayout.parseInstance(Exe_01.class).toPrintable());synchronized (Exe_01.class) {//加锁后的类对象System.out.println("+++++对类对象加锁后,不同的对象获取锁,观察锁升级为thin lock");System.out.println(ClassLayout.parseInstance(Exe_01.class).toPrintable());}//释放锁之后的类对象System.out.println("+++++释放锁后");System.out.println(ClassLayout.parseInstance(Exe_01.class).toPrintable());System.out.println("+++++多个锁线程参与锁竞争,观察锁状态+++++");Thread thread1 = new Thread(() -> {synchronized (monitor) {System.out.println("=== 在线程A 中获取锁,参与锁竞争,当前只有线程A 竞争锁,轻度锁竞争");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());}});thread1.start();// 休眠一会,不与线程A 激烈竞争Thread.sleep(100);Thread thread2 = new Thread(() -> {synchronized (monitor) {System.out.println("=== 在线程B 中获取锁,与其他线程进行锁竞争");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());}});thread2.start();// 不休眠直接竞争锁,产生激烈竞争System.out.println("==== 不休眠直接竞争锁,产生激烈竞争");synchronized (monitor) {// 加锁后的类对象System.out.println("==== 与线程B 产生激烈的锁竞争,观察锁状态为fat lock");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());}// 休眠一会释放锁后Thread.sleep(100);System.out.println("==== 释放锁后");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());System.out.println("===========================================================================================");// 调用hashCode后才保存hashCode的值monitor.hashCode();// 调用hashCode后观察现象System.out.println("==== 调用hashCode后查看hashCode的值");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());// 强制执行垃圾回收System.gc();// 观察GC计数System.out.println("==== 调用GC后查看age的值");System.out.println(ClassLayout.parseInstance(monitor).toPrintable());// 打印类布局,注意调用的方法不同System.out.println("==== 查看类布局");System.out.println(ClassLayout.parseClass(Exe_01.class).toPrintable());// 打印类对象布局System.out.println("==== 查看类对象布局");System.out.println(ClassLayout.parseInstance(Exe_01.class).toPrintable());}
}class TextExe_01 {}
结果分析:
里面的参数类型可参考这篇文章-Java对象的内存布局 - JaJian - 博客园 (cnblogs.com)
三、其它的优化操作
3.1、锁消除
synchronized的一种优化策略
synchronized是手动添加的自己获取到锁的处理逻辑,什么时候加,加在哪里,JVM无法去管理,但是在代码编译和运行的时候,JVM可以知道程序是读变量,还是写变量。
如果我们手动对所有的读操作都加了synchronized关键字,但是又没有写操作,,那么这个时候JVM就认为这个锁是多余的,那么synchronized就不会去枷锁了,这种现象就叫做”锁消除“。
注意:
多线程状态下,多线程对同一个变量进行修改才会有线程安全问题,而多线程对同一个变量读取没有线程安全问题。
synchronized只有100%确定不需要锁的时候,才会进行锁消除优化 。
3.2、锁粗化
一段逻辑中如果出现多次加锁解锁,编译器JVM就会自动进行锁粗话。
真实的代码执行过程,从方法1到方法5全部都执行完,才结束。
如上面的流程中每一个方法都会有一个申请锁资源,释放锁资源的流程。
那么对于这种现象,synchronized就会认为从头到尾只需要获取一次锁资源,中途不会释放锁。
这个现象就叫“锁粗化”,从方法级别(细粒度变成了业务级别的粗粒度)。
相关文章:

synchronized原理
目录 一、基本特点 二、加锁过程 2.1、偏向锁 2.2、轻量级锁 2.3、重量级锁 三、其它的优化操作 3.1、锁消除 3.2、锁粗化 一、基本特点 synchronized有以下特性: 开始是乐观锁,如果锁冲突频繁,就转换为悲观锁。开始是轻量级锁,…...
10G光模块能兼容千兆光口吗
当涉及到光网络设备和光模块的兼容性时,确保正确的匹配是至关重要的。本期文章内容,我们将探讨10G光模块与千兆光口之间的兼容性。 一、10G光模块和千兆光口的基本概念 首先,我们需要了解10G光模块和千兆光口的基本概念。10G光模块是一种用…...
css 显示省略号 和 动态显示省略号
省略是非常常见的功能。 简单的实现省略号 下面的代码就可以实现省略号,超过宽度的时候就会出现省略号 .text-name{//宽高是一定要设置的不然是会无效延伸的width: 200rpx;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}稍微复杂点的情况&#…...
LeetCode 1253. 重构 2 行二进制矩阵
【LetMeFly】1253.重构 2 行二进制矩阵 力扣题目链接:https://leetcode.cn/problems/reconstruct-a-2-row-binary-matrix/ 给你一个 2 行 n 列的二进制数组: 矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。第 0 行的元素之…...
【八股】【C++】内存
这里写目录标题 内存空间分配new和delete原理C有几种newmalloc / free 与 new / delete区别malloc和free原理?delete和delete[]区别?C内存泄漏malloc申请的存储空间能用delete释放吗?malloc、calloc函数、realloc函数C中浅拷贝与深拷贝栈和队列的区别C里…...
数据库G等待
> db^Cgbasedbtpc:~$ dbaccess db10 -Database selected.> call insert_t();Routine executed.Elapsed time: 811.630 sec 磁盘逻辑日志,无BUF库> ^Cgbasedbtpc:~$ gbasedbtpc:~$ dbaccess db10 -Database selected.> call insert_t();Routine executed.Elapse…...
PCB封装设计指导(一)基础知识
PCB封装设计指导(一)基础知识 PCB封装是PCB设计的基础,也是PCB最关键的部件之一,尺寸需要非常准确且精确,关系到设计,生产加工,贴片等后续一系列的流程。 下面以Allegro为例介绍封装创建前的一些基础知识 1.各个psm文件代表什么 mechanical symbol 是.bsm Package sy…...
Flask框架之Restful--介绍--下载--基本使用
目录 Restful 概念 架构的主要原则 适用场景 协议 数据传输格式 url链接规则 HTTP请求方式 状态码 Restful的基本使用 介绍 优势 缺点 安装 基本使用 注意 Restful 概念 RESTful(Representational State Transfer)是一种用于设计网络应用…...

2023年上海市浦东新区网络安全管理员决赛理论题样题
目录 一、判断题 二、单选题 三、多选题 一、判断题 1.等保1.0至等保2.0从信息系统拓展为网络和信息系统。 正确 (1)保护对象改变 等保1.0保护的对象是信息系统,等保2.0增加为网络和信息系统,增加了云计算、大数据、工业控制系统、物联网、移动物联技术、网络基础…...

SQL语言的四大组成部分——DCL(数据控制语言)
1️⃣前言 SQL语言中的DCL(Data Control Language)是一组用于控制数据库用户访问权限的语言,主要包括GRANT、REVOKE、DENY等关键字。 文章目录 1️⃣前言2️⃣DCL语言3️⃣GRANT关键字4️⃣REVOKE关键字5️⃣DENY关键字6️⃣总结附࿱…...

ChatGPT新功能曝光:可记住用户信息、上传文件和工作区
🦉 AI新闻 🚀 ChatGPT新功能曝光:可记住用户信息、上传文件和工作区 摘要:一张神秘截图曝光了ChatGPT新功能,包括可记住用户信息的"My profile"、上传和管理文件的"My files"以及可以让AI使用不…...

【Unity编辑器扩展】(三)PSD转UGUI Prefab, 一键拼UI解放美术/程序(完结)
工具效果: 第一步,把psd图层转换为可编辑的节点树,并自动解析UI类型、自动绑定UI子元素: 第二步, 点击“生成UIForm"按钮生成UI预制体 (若有UI类型遗漏可在下拉菜单手动点选UI类型): 验证一键生成UI效果: 书接上…...

SpringBoot开发Restful风格的接口实现CRUD功能
基于SpringBoot开发一个Restful接口 前言一、什么是SpringBoot?二、实战---基于SpringBoot开发一个Restful接口1.开发前的准备工作1.1 添加相关依赖 (pom文件) 1.2 创建相关数据库和表1.3 数据库配置文件 2.实战开发---代码逻辑2.1 实体类2.2…...

【Servlet学习三】实现一个内存版本的简易计算器~
目录 一、方式1:使用form表单的形式(不推荐) 🌈1、前端代码:HTML文件 🌈2、后端代码:Calculator_form.java文件 🌈3、最终效果 二、方式2:使用ajax形式(…...
Linux c语言获取本机网关 ip 地址
文章目录 前言一、获取本机网关 ip 地址1.1 代码示例1.2 代码详解介绍 二、使用Netlink套接字实时监控网络事件2.1 简介2.2 示例代码 前言 这篇文章写了获取本机的ip地址和子网掩码:Linux c语言获取本机 ip、子网掩码 一、获取本机网关 ip 地址 使用Netlink套接字…...

nginx部署本地项目如何让异地公网访问?服务器端口映射配置!
接触过IIS或apache的小伙伴们,对nginx是比较容易理解的,nginx有点类似,又有所差异,在选择使用时根据自己本地应用场景来部署使用即可。通过一些对比可能会更加清楚了解: 1.nginx是轻量级,比apache占用更少…...

云时代已至,新一代数据分析平台是如何实现的?
2023 年 5 月,由 Stackoverflow 发起的 2023 年度开发者调查数据显示,PostgreSQL 已经超越 MySQL 位居第一,成为开发人员首选。PostgreSQL 在国内的热度也越来越高。6 月 17 日,PostgreSQL 数据库技术峰会在成都顺利召开。本次大会…...

【C#】简单聊下Framework框架下的事务
框架用的多了,之前版本的事务都忘记了。本次简单聊下.net framework 4.8框架下本身的事务 目录 1、SqlClient2、TransactionScope3、引用 1、SqlClient 在 C# 中,使用 using 块可以方便地实现对资源的自动释放,但它不适用于实现事务处理。为…...
asyncPool并发执行请求函数
asyncPool应用场景 一个不太常见的极端场景,当我们为了某个操作需要发生异步请求的时候,等待所有异步请求都完成时进行某些操作。这个时候我们不在简简单单的发送 1 - 2 个请求而是 5 - 10个(其实极端场景式 很多很多个请求,这个…...
Ubuntu 22.04上安装NFS服务
1、使用如下命令安装NFS服务端软件: # 在主机上运行以下命令 orangepiorangepi5:~$ sudo apt install nfs-server 2、在配置NFS时需要使用用户uid和组gid,可以使用id命令查看 # 在主机上运行id命令 orangepiorangepi5:~$ id uid1000(orangepi) gid100…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...