synchronized进阶原理
synchronized进阶原理
1.轻量级锁
轻量级锁的使用场景:如果一个对象虽然有多个线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化(如果出现竞争,操作系统会将轻量级锁升级为重量级锁)。轻量级锁对使用者是透明的(由操作系统控制),即语法仍是synchronized。
假设有两个方法同步块,利用同一个对象加锁
static final Object obj = new Object();
public static void method1(){synchronized(obj){//同步块Amethod2();}
}
public static void method2(){synchronized(obj){//同步块B}
}
创建锁记录(Lock Record)对象,每个线程的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word

让锁记录中Object reference 指向锁对象,并尝试用cas替换Object的Mark Word,将Mark Word的值存入锁记录(01代表未上锁,00代表上轻量级锁)

如果cas替换成功,对象头中存储了锁记录地址和状态00,表示由该线程给对象加锁

如果cas失败,有两种情况
· 如果其它线程已经持有了该Object的轻量级锁,这时表明有竞争,进入锁膨胀过程
· 如果是自己执行了synchronized锁重入(自己又对synchronized加锁了),那么再添加一条Lock Record作为重入的计数

当退出synchronized代码块(解锁时)如果有取值为null的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

当退出synchronized代码块(解锁时)锁记录的值不为null,这时使用cas将Mark Word的值恢复给对象头
· 成功,则解锁成功
· 失败,说明轻量级锁进行了膨胀或已经升级为重量级锁,进入重量级锁解锁流程
2.锁膨胀
如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。
static Object obj = new Object();
public static void method1(){synchronized(obj){//同步块}
}
当Thread-1进行轻量级锁时,Thread-0已经对该对象加了轻量级锁

这时Thread-1加轻量级锁失败,进入锁膨胀流程
· 即为Object对象申请Monitor锁,让Object指向重量级锁地址
· 然后自己进入Monitor的EntryList中 BLOCKED

当Thread-0退出同步代码块解锁时,使用cas将Mark Word的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照Monitor地址找到Monitor对象,设置Owner为null,唤醒EntryList中BLOCKED线程,从它们中竞争出下一个与Owner关联的线程
3.自旋优化
重量级锁竞争的时候,还可以使用自旋锁来进行优化,如果当前线程自旋锁成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。
自选重试成功的情况

自旋重试失败的情况

在java6之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋。自旋会占用CPU时间,单核CPU自旋就是浪费,多核CPU自旋才能发挥优势。java7之后不能控制是否开启自旋功能。
4.偏向锁
轻量级锁在没有竞争时(就自己这个线程),每次重入仍需要执行CAS操作。java6中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS。以后只要不发生竞争,这个对象就归该线程所有。
static final Object obj = new Object();
public static void m1(){synchronized(obj){//同步块Am2();}
}
public static void m2(){synchronized(obj){//同步块Bm3();}
}
public static void m3(){synchronized(obj){//同步块C}
}


偏向状态
对象头:

biased_lock 用于记录是否启动偏向锁(0为未启动)
thread 是线程id(操作系统给的,和java中自己设置的不同)
一个对象创建时:
· 如果启动了偏向锁(默认开启),那么对象创建后,markword值为0x05即最后3位为101,这时它的thread、epoch、age都是0
· 偏向锁默认是延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加VM参数 - XX:BiasedLockingStartupDelay=0来禁止延迟
· 如果没有开启偏向锁,那么对象创建后,markword值为0x01即最后3位为001,这时它的hashcode、age都为0,第一次用到hashcode时才会赋值
测试禁用:在上面测试代码运行时在添加VM参数 -XX: -UseBiasedLocking 禁用偏向锁
测试hashCode:当对用对象的hashCode()时,偏向锁会被撤销,对象就会变成普通状态(当轻量级锁对象调用hashCode()时,hashCode会记录在栈帧中的锁记录里,当重量级锁调用hashCode()时,hashCode会存在monitor对象里)
撤销偏向锁-其它线程使用对象
当有其他线程使用偏向锁对象时,会将偏向锁升级为轻量级锁。
撤销偏向锁-使用wait/notify
批量重偏向
如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程T1的对象仍有机会重新偏向T2,重偏向会重置对象的Thread ID
当撤销偏向锁阈值超过20次后,JVM会在给这些对象加锁时重新偏向至加锁线程。
批量撤销
当撤销偏向锁阈值超过40次后,JVM会觉得不该偏向。于是整个类的所有对象都会变为不可偏向的,新建的对象也是不可偏向的。
锁撤销
java有即时编译器(JIT),会对代码进行优化,将一些无用的锁优化掉了
相关文章:
synchronized进阶原理
synchronized进阶原理 1.轻量级锁 轻量级锁的使用场景:如果一个对象虽然有多个线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化(如果出现竞争,操作系统会将轻量级锁升级为重量级锁)。轻量级锁对使用者是透明的(由操作系统控制),即语法仍是s…...
C++,STL 052(24.10.29)
内容 1.对map容器的大小进行操作。 2.map容器的交换操作。 运行代码 #include <iostream> #include <map>using namespace std;void printMap(map<int, int> &m) {for (map<int, int>::iterator it m.begin(); it ! m.end(); it){cout <<…...
git下载和配置
git是什么? Git是一种分布式版本控制系统,用于跟踪文件的变化,尤其是源代码。它允许多个开发者在同一项目上进行协作,同时保持代码的历史记录。Git的主要特点包括: 分布式:每个开发者都有项目的完整副本&a…...
Linux基础—基础命令及相关知识5(ubuntu网络配置)
网络的配置方法 centos网络配置 centos的网卡位置 /etc/sysconfig/network-scripts/ifcfg-ens33(centos网卡文件) bootproto表示获得IP地址的方式是静态的还是动态 onboot表示启动系统时是否激活该网络接口 设置IP地址,子网掩码,网关,dns…...
使用 firewall-cmd 管理 Linux 防火墙
firewalld-cmd命令翻译<一> Linux 系统中,firewalld 是一个流行的动态防火墙管理工具, firewall-cmd 是它的命令行接口。通过 firewall-cmd,可以轻松地管理防火墙规则、配置区域(zones)、处理端口等。 这篇文章…...
鸿蒙OS试题
哪些是持续部署最佳实践? A. 灰度发布:先在小部分用户或区域进行部署,观察没问题后再全面推广 B.手工部署:持续部署可以采用手工部署的方式发布软件: 1、有一份非常详尽的文档,该文档描述了执行步骤及每个步骤中易出错的地方; 2、以手工测试来确认该…...
Flutter InkWell组件去掉灰色遮罩
当InkerWell组件内部获取到焦点时,会展示一层灰色遮罩 将focusColor属性设置为透明即可 Flutter InkWell焦点效果源码分析 问题描述 当 InkWell 组件获得焦点时,会显示一层灰色遮罩效果。需要找出这个效果是由哪些组件控制的,以及具体的…...
Android——metaData
获取元数据信息的步骤: 调用 getPackageManager 方法获得当前应用的包管理器调用包管理器的 getActivityInfo 方法获得当前活动的信息对象活动信息对象的 metaData 是 Bundle 包裹类型,调用包裹对象的 getString 即可获得指定名称的参数值 配置 metaDa…...
SLAM|1. 相机投影及相机畸变
一个能思考的人,才真是一个力量无边的人。——巴尔扎克 本章主要内容: 1.针孔相机模型 2.相机成像的几个坐标系图像 3.畸变及相机标定 本节主要介绍在照相机拍摄过程中,现实物体如何跟照片上的像素关联起来,具体涉及相机成像的物…...
nginx配置及虚拟主机
nginx配置及虚拟主机 一、http协议介绍1、网站类型2、涉及的软件3、http协议介绍 二、nginx安装、启动1、nginx介绍2、nginx安装3、nginx启动管理 三、nginx配置文件1、配置文件语法结构2、全局配置3、事件驱动模型的配置4、http的配置 四、虚拟主机配置1、类型2、基于名称的虚…...
ElasticSearch - Bucket Script 使用指南
文章目录 官方文档Bucket Script 官文1. 什么是 ElasticSearch 中的 Bucket Script?2. 适用场景3. Bucket Script 的基本结构4. 关键参数详解5. 示例官方示例:计算每月 T 恤销售额占总销售额的比率百分比示例计算:点击率 (CTR) 6. 注意事项与…...
Android的SQLiteOpenHelper类 笔记241027
SQLiteOpenHelper SQLiteOpenHelper是Android开发中用于管理SQLite数据库的一个非常重要的工具类。以下是对SQLiteOpenHelper的详细介绍: 一、基本概念 SQLiteOpenHelper是一个抽象类,它主要用于管理数据库的创建和版本管理。通过继承这个类ÿ…...
「Mac畅玩鸿蒙与硬件10」鸿蒙开发环境配置篇10 - 项目实战:计数器应用
本篇将通过一个简单的计数器应用,带你体验鸿蒙开发环境的实际操作流程。本项目主要练习组件的使用、事件响应和状态管理,帮助开发者熟悉基本的应用构建流程。 关键词 计数器应用组件操作事件响应状态管理HarmonyOS 应用开发一、创建计数器项目 1.1 在 DevEco Studio 中新建项…...
安卓逆向之ARM汇编寻址,汇编指令
一:ARM汇编寻址 1. 立即数寻址 (Immediate Addressing) 指令中直接给出一个常数值(立即数),并对其进行操作。 MOV R0, #5 ; 将立即数5载入寄存器R02. 直接寻址 (Direct Addressing) 指令中给出的地址直接指定了内存中的一…...
Idea常见插件(超级实用)
文章目录 Idea好用的插件推荐Idea插件安装Chinese(中文版)Alibaba Java Coding Guidelines(代码规范)Auto Filling Java Arguments(自动补全参数)CamelCase(变量名称格式转换)CodeGeeX(智能&…...
C++中如何获取时间并格式化为字符串?
在C中,你可以使用标准库中的 <chrono> 和 <iomanip> 头文件来获取当前时间并将其格式化为字符串。以下是一个简单的示例,展示了如何获取当前时间并将其格式化为一个可读的字符串(例如:YYYY-MM-DD HH:MM:SS)…...
项目1 yolov5鱼苗检测计数
yolov5鱼苗检测 1. yolov5鱼苗检测1.1. 环境配置1.2 Predict1.3 Validate1.4 Train1.5 生成 ONNX 2 代码解析2.1 模型2.2 数据集2.3 损失函数2.4 训练2.5 预测 之前做的项目,再回顾一下 环境:GPU1卡,CPU4核,每显卡12GB,…...
GPU 学习笔记三:GPU多机多卡组网和拓扑结构分析(基于数据中心分析)
文章目录 一、概述二、数据中心(DC)2.1 数据中心简介2.2 传统数据中心的网络模型2.3 脊叶网络模型(Spine-Leaf)2.4 Facebook的Fabric网络架构 三、基于数据中心的多机多卡拓扑3.1 Spine-Leaf 架构网络规模测算方法3.2 NVIDIA多机多…...
各编程语言处理HTTP状态码的库推荐
Http 状态码用那个库 备注 Spring 的状态码库为 org.springframework.http.HttpStatus Apache 的状态码库为: org.apache.http.HttpStatus 通常这 2 个库都差不多。 如你的项目中已经用了 Spring 的代码的话,那么就用 Spring 的库吧。 不管是那个库…...
【Mac】Python 环境管理工具
一、pyenv 1、安装 (1)安装 brew install pyenv(2)环境配置 查看系统使用 shell 是 bash 还是 zsh bash 配置文件:~/.bash_profile zsh 配置文件:~/.zshrc userMac ~ % echo $SHELL /bin/zsh userMa…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
