synchronized关键字的使用和原理
synchronized关键字的使用和原理
synchronized:对象锁,保证了临界区内代码的原子性,采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其它线程获取这个对象锁时会阻塞,保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换。
1、使用方式:
锁对象:理论上可以是任意的唯一对象
package com.jtc.fe;public class synchronizedDemo {// 同步静态方法 ——> 锁住class类对象 ——> 全局唯一synchronized public static void func1(){}// 同步方法 ——> 锁住实例对象 ——> 每个实例都可以当锁synchronized public void func3(){}// 同步代码块public void func2(){// ——> 锁住class类对象 ——> 全局唯一synchronized (synchronizedDemo.class){}}public void func4(){// ——> 锁住实例对象 ——> 每个实例都可以当锁synchronized (this){}}public void func5(){// ——> 锁住字符串"123"synchronized ("123"){}}
}
注意:
synchronized 修饰的方法的不具备继承性,所以子类是线程不安全的,如果子类的方法也被 synchronized 修饰,两个锁对象其实是一把锁,而且是子类对象作为锁。
2、锁原理
Java的对象由三部分组成:对象头 + 实例数据 + 对齐填充。
2.1、对象头
64位对象头由Mark Word、Class Pointer两部分组成,如果对象是数组,则还要加上数组长度,即三部分组成。
Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。由于对象需要存储的运行时数据很多,但64位虚拟机给它的空间只有64位Bitmap,所以Mark Word被设计成一个有着动态定义的数据结构,即不同的锁状态存储内容不同。

如果要查看内存结构图,需要引入依赖:
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.9</version>
</dependency>
import com.example.demo.User;
import org.openjdk.jol.info.ClassLayout;public class p6 {static User user = new User();static User[] users = new User[10];public static void main(String[] args) {System.out.println(ClassLayout.parseInstance(user).toPrintable());System.out.println("*******************************************");System.out.println(ClassLayout.parseInstance(users).toPrintable());}
}

Mark Word由64位8个字节组成。Class Pointer由64位8个字节组成,但我们使用的64位 JVM会默认使用选项 +UseCompressedOops 开启指针压缩,将指针压缩至32位。即上面截图中的Class Pointer为4个字节32位。
如果在打印对象头前调用HashCode方法,则会变成如下:

从MarkWord的结构可以看出,在无锁阶段内存分布与上图是一一对应的,HashCode也是一一对应的。
2.2、锁升级
synchronized 是可重入、不公平的重量级锁,所以可以对其进行优化。
无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 // 随着竞争的增加,只能锁升级,不能降级
其中重量级锁还需要Monitor对象配合使用

偏向锁
偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程之后重新获取该锁不再需要同步操作:当锁对象第一次被线程获得的时候进入偏向状态,使用 CAS 操作将线程 ID 记录到 Mark Word。
轻量级锁
当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定或轻量级锁状态。一个对象有多个线程要加锁,但加锁的时间是错开的(没有竞争),可以使用轻量级锁来优化,轻量级锁对使用者是透明的(不可见)。
重量级锁
在尝试加轻量级锁的过程中,CAS 操作无法成功,可能是其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。
在重量级锁阶段,每个 Java 对象都可以关联一个 Monitor 对象,Monitor 也是 class,其实例存储在堆中,如果使用 synchronized 给对象上锁之后,该对象头的 Mark Word 中就被设置指向 Monitor 对象的指针,这就是重量级锁。

工作流程:
-
开始时 Monitor 中 Owner 为 null
-
当 Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor 中只能有一个 Owner,obj 对象的 Mark Word 指向 Monitor,把对象原有的 MarkWord 存入线程栈中的锁记录中
-
在 Thread-2 上锁的过程,Thread-3、Thread-4、Thread-5 也执行 synchronized(obj),就会进入 EntryList BLOCKED(双向链表)
-
Thread-2 执行完同步代码块的内容,根据 obj 对象头中 Monitor 地址寻找,设置 Owner 为空,把线程栈的锁记录中的对象头的值设置回 MarkWord
-
唤醒 EntryList 中等待的线程来竞争锁,竞争是非公平的,如果这时有新的线程想要获取锁,可能直接就抢占到了,阻塞队列的线程就会继续阻塞
-
WaitSet 中的 Thread-0,是以前获得过锁,但条件不满足进入 WAITING 状态的线程(wait-notify 机制)
2.3、代码字节码
修饰代码段时:
public static void main(String[] args) {Object lock = new Object();synchronized (lock) {System.out.println("ok");}
}
0: new #2 // new Object
3: dup
4: invokespecial #1
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter // 【将 lock对象 MarkWord 置为 Monitor 指针】
12: getstatic #3
15: ldc #4
17: invokevirtual #5
20: aload_2
21: monitorexit // 【将 lock对象 MarkWord 重置, 唤醒 EntryList】
22: goto 30
25: astore_3
26: aload_2
27: monitorexit // 【将 lock对象 MarkWord 重置, 唤醒 EntryList】
28: aload_3
29: athrow
30: return
Exception table:from to target type12 22 25 any25 28 25 any
LineNumberTable: ...
LocalVariableTable:Start Length Slot Name Signature0 31 0 args [Ljava/lang/String;8 23 1 lock Ljava/lang/Object;
从上面我们可以看出:synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。其中两个 monitorexit 指令是为了保证锁在同步代码块代码正常执行以及出现异常的这两种情况下都能被正确释放。
修饰方法时:
public synchronized void method() {System.out.println("synchronized 方法");
}
JVM 通过该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否声明为同步方法,如果是实例方法,JVM 会尝试获取实例对象的锁。如果是静态方法,JVM 会尝试获取当前 class 的锁。
总结:
synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,修饰方法是 ACC_SYNCHRONIZED 标识。
不过两者的本质都是对对象监视器 Monitor 的获取。
参考:https://github.com/Seazean/JavaNote/blob/main/Prog.md
https://blog.csdn.net/zhaocuit/article/details/100208879?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170239663116800182715111%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=170239663116800182715111&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-100208879-null-null.142v96pc_search_result_base9&utm_term=java%E5%AF%B9%E8%B1%A1%E5%A4%B4&spm=1018.2226.3001.4187
相关文章:
synchronized关键字的使用和原理
synchronized关键字的使用和原理 synchronized:对象锁,保证了临界区内代码的原子性,采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其它线程获取这个对象锁时会阻塞,保证拥有锁的线程可以安全的执行临界区内…...
【PHP】php发送邮箱验证码格式美化,样式美化
效果展示: 格式美化前 格式美化后 代码 大多数框架都自带有封装好的发送email方法,就不多赘述,主要写格式: <? php// 验证码过期时间 $expire 120; // 发件人邮箱 $from_email xx163.com; // 收件人 $to_email to163.com…...
【EI会议征稿中】2024年第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)
2024年第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024) 2024 4th International Conference on Artificial Intelligence, Automation and High Performance Computing 2024第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)将于20…...
数据库设计规范编制文档
本文的目的是提出针对Oracle数据库的设计规范,使利用Oracle数据库进行设计开发的系统严格遵守本规范的相关约定,建立统一规范、稳定、优化的数据模型。 参照以下原则进行数据库设计: 1) 方便业务功能实现、业务功能扩展; 2) 方便设…...
RocketMq集成SpringBoot(待完善)
环境 jdk1.8, springboot2.7.3 Maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from…...
刚学Python有点难怎么办?这是好事啊!
对于像我一样非计算机专业出身的学生,每当我们想自学一些编程技能的时候,就感觉困难重重,思考坚持下去有没有意义,因此我总结了以下7个小Tips,这些Tips曾经帮助我合理地安排时间,让自学Python的节奏保持起来…...
LNMP网站架构分布式搭建部署
1. 数据库的编译安装 1. 安装软件包 2. 安装所需要环境依赖包 3. 解压缩到软件解压缩目录,使用cmake进行编译安装以及模块选项配置(预计等待20分钟左右),再编译及安装 4. 创建mysql用户 5. 修改mysql配置文件,删除…...
lwIP 细节之六:connected、sent、poll 回调函数是何时调用的
使用 lwIP 协议栈进行 TCP 裸机编程,其本质就是编写协议栈指定的各种回调函数。将你的应用逻辑封装成函数,注册到协议栈,在适当的时候,由协议栈自动调用,所以称为回调。 注:除非特别说明,以下内…...
C语言搭建项目-学生管理系统(非链表)
、 目录 搭建offer.h文件 搭建offer.c中的main函数 密码登入系统 搭建my_oferr.c中的接口函数 使用帮助菜单接口函数 增加学生信息接口函数 查询学生信息接口函数 删除学生信息接口函数 保存学生信息接口 打开文件fopen 关闭文件fclose 判断是否保存文件fwrite 退出执行文件…...
美易官方:投资美股证券投资组合的优势及快速上手指南
投资美股证券投资组合的优势及快速上手指南 美股证券投资组合的优势 美国股市一直以来都是全球投资者的热门选择之一。与其他市场相比,美国股市具有诸多优势,如市场规模大、流动性好、信息透明度高等。投资者在美国股市中,可以选择各种不同类…...
centos日常运维随记
# 需要生成随机字符及数字 rootAAA:~# echo $RANDOM | md5sum |cut -c 3-29 e7e8942a791146531f613c7c757 # echo $RANDOM 产生随机数据 # md5sum 随机数生成md5值 # cut -c 3-29 :md5产生的是32的md5数,使用cut -c 对这个数进行 第3位到第29位的截取# 在现有的…...
设计模式之观察者模式(主题对象发生变化,通知各个观察者)
当涉及到电商场景时,观察者模式可以用于处理多种情况,比如订单状态更新、库存变化、用户积分变化等。下面是一个简化的订单状态更新的观察者模式案例。 1.首先,定义一个主题接口 OrderSubject /*** Description:主题,用于管理观察…...
vue+高德,百度地图
1,npm安装vue-amap npm install vue-amap --save 2,main.js引入 import VueAMap from vue-amap; Vue.use(VueAMap); VueAMap.initAMapApiLoader({key: ,plugin: [AMap.Autocomplete, AMap.PlaceSearch, AMap.Scale, AMap.OverView, AMap.ToolBar, AMap.…...
工信部举行发布会 数字化产业推动元宇宙发展取得良好成效
据官方消息,工业和信息化部12日举行“发挥国家高新区作用 加快推进新型工业化”新闻发布会。 在数字化建设方面取得了良好的成绩: 一是数字经济加速发展。国家高新区着力推动人工智能、大数据、云计算、区块链和元宇宙等新产业新业态蓬勃发展ÿ…...
有没有手机电脑同步的工作时间管理软件?
越来越多的职场人士感到每天的工作任务是比较多的,而工作时间又是有限的,所以经常时间不够用。因此,对于上班族来说,高效的时间管理是提高工作效率、按时完成任务的关键。为了满足这一需求,很多网友都在寻找一款既能在…...
docker安装及简单使用(Linux版本)
文章目录 前言一、docker安装二、docker命令pull(安装镜像)rmi(删除镜像)images(查看镜像)run(创建容器)删除容器exec(进入运行中的容器)常用命令 总结如有启…...
山西电力市场日前价格预测【2023-12-10】
1.日前价格预测 预测说明: 如上图所示,预测明日(2023-12-10)山西电力市场全天平均日前电价为384.75元/MWh。其中,最高日前价格为493.66元/MWh,预计出现在16: 00。最低日前电价为282.24元/MWh,预…...
在OpenCV基于深度学习的超分辨率模型实践
1. 引言 OpenCV是一个开源的计算机视觉库,拥有大量优秀的算法。基于最新的合并,OpenCV包含一个易于使用的接口,主要用于实现基于深度学习方法的超分辨率(SR)。该接口包含预先训练的模型,这些模型可以非常容…...
beebox靶场A3 中等级别 xss通关教程
特别注意,低级和中级的差别在于中级使用了一些函数进行了过滤或转义字符 例如 addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。 预定义字符是: 单引号()双引号(")反斜杠(\&…...
前端知识笔记(二)———Django与Ajax
特点: 异步提交 局部刷新 例子:github注册 动态获取用户名实时的跟后端确认并实时的展示到前端(局部刷新) 朝后端发送请求的方式 1.浏览器地址栏直接输入url回车 -----》get请求 2.a标签的href属性 -----》get请求 3…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...
中国政务数据安全建设细化及市场需求分析
(基于新《政务数据共享条例》及相关法规) 一、引言 近年来,中国政府高度重视数字政府建设和数据要素市场化配置改革。《政务数据共享条例》(以下简称“《共享条例》”)的发布,与《中华人民共和国数据安全法》(以下简称“《数据安全法》”)、《中华人民共和国个人信息…...
