synchronized 之谜

序言

本文给大家介绍一下 synchronized 关键字的部分原理。

一、内存中的 Java 对象

class A {private String attr;
}

先引入一个问题:上面类 A 有一个属性 attr。当类 A 实例化之后的对象在内存中是如何表示的呢?

workspace.png

在内存中,Java 对象由三部分组成。其中包括对象头(Header)、实例数据(Instance Data)和对齐填充 (Padding)等部分。

  1. 对象头(Object Header):对象头存储了对象的元数据信息,比如哈希码、锁状态、垃圾回收标记等。对象头的大小在 32 位和 64 位的 JVM 上可能会有所不同,通常占用 8 字节或更多的空间。
  2. 实例数据(Instance Data):实例数据是对象的成员变量(字段)的实际存储区域。每个字段根据其类型占用不同的内存空间。例如,一个 int 类型的字段占用 4 字节,一个对象引用占用 4 字节(在 32 位 JVM 上)或 8 字节(在 64 位 JVM 上)。
  3. 对齐填充(Padding):由于硬件要求数据在内存中的地址是对齐的,因此在实例数据和对象头之间可能存在一些填充字节,以保证对象的起始地址是对齐的。填充的大小通常是对象头和实例数据大小的倍数,以满足对齐要求。

二、Java 对象头

对象头包含了两部分,分别是运行时元数据(Mark Word)和类型指针(Klass Word)。

workspace (1).png

在 32 位的虚拟机中,对象头占 64 位。其中 Mark Word 占 32 位,Klass Word 占 32 位。

workspace (2).png

在 64 位的虚拟机中,对象头占 128 位。其中 Mark Word 占 64 位,Klass Word 占 64 位。
接下来我们以 64 位的虚拟机为例。

三、Mark Word

对象头的 Mark Word 存储了对象的元信息,其中包括了对象的锁状态、GC(垃圾回收)相关信息等。 Mark Word 中通常用来表示对象的锁状态的部分称为锁标志位 (Lock Word),它包含了对象的锁状态、线程 ID 等信息。

通常情况下,锁标志位可以有以下几种状态:

  1. 无锁状态:对象尚未被锁定,可以被任意线程访问。
  2. 偏向锁状态:对象已经被某个线程锁定,但是尚未涉及竞争。在这种状态下,MarkWord 中会记录拥有锁的线程 ID,并且对象的锁标志位中会设置偏向锁标志。
  3. 轻量级锁状态:多个线程竞争同一个锁,但尚未涉及到真正的阻塞,因此采用了一种轻量级的锁机制来进行竞争。在这种状态下,MarkWord 中会记录锁的指针,用于指向锁记录(Lock Record),并且对象的锁标志位中会设置轻量级锁标志。
  4. 重量级锁状态:当轻量级锁竞争不过,会升级为重量级锁,这时会涉及到阻塞和唤醒线程的操作。在这种状态下,MarkWord 中不再存储锁记录的指针,而是直接指向锁对象,并且对象的锁标志位中会设置重量级锁标志。
  5. GC 标志位:有些 JVM 实现中,MarkWord 还可能包含 GC 相关的标志位,用于标记对象是否被回收等信息。

3.1 无锁状态的 Mark Word

workspace.png

上图是 64 位虚拟机中无锁状态的 Mark Word。表示无锁是 Mark Word 的后三位(Mark Word 后三位 001 表示无锁),即:baised_lock 标志位是 0,Mark Word 最后两位是 01。

3.2 偏向锁状态的 Mark Word

workspace (1).png

上图是 64 位虚拟机中偏向锁状态的 Mark Word。表示偏向锁是 Mark Word 的后三位(后三位 101 表示偏向锁),即:baised_lock 标志位是 1,Mark Word 最后两位是 01。

3.3 轻量级锁状态的 Mark Word

workspace.png

上图是 64 位虚拟机中轻量级锁状态的 Mark Word。后两位 00 表示轻量级锁。

3.4 重量级锁状态的 Mark Word

workspace.png

上图是 64 位虚拟机中重量级锁状态的 Mark Word。后两位 10 表示轻量级锁。

3.5 GC 标志位的 Mark Word

workspace (1).png
上图是 64 位虚拟机中 GC 标志位的 Mark Word。后两位 11 表示 GC 标志位。

四、synchronized 工作流程

class A {private String attr;public void setAttr(String attr) {// 使用 synchronized 加锁synchronized (this) {this.attr = attr;}}
}

在上述代码中,setAttr() 方法中使用了 synchronized,其中锁住的是当前对象 A。

  1. 当使用 synchronized 锁住对象 A ,对象 A 未被使用时,对象 A 的 Mark Word 依旧没有改变(即 Mark Word 后三位是 001,无锁状态)。
  2. 当第一次有一个线程去访问对象 A 时,此时 Mark Word 的锁标志位会变成 101(即表示对象现在使用的偏向锁)。
  3. 若后面有少量其他线程也去获取对象 A 的锁,对象 A 会先撤销偏向锁,偏向锁撤销成功则尝试采用 CAS 加上轻量级锁,轻量级锁加锁成功则将 Mark Word 的锁标志位变成 00(即表示对象现在使用的轻量级锁)
  4. 若后面有更多的线程前来争抢对象 A 的锁,其他未抢到锁的线程就会发生 CAS 自旋。自旋超时之后,系统便判断当前对于该锁的竞争非常激烈,将会撤销轻量级锁,然后加上重量级锁,并将锁标志位相应地更新为重量级锁即 10

在这里插入图片描述

通过上面的分析,我们知道 synchronized 在底层存在一种锁升级机制而不是使用一种固定的锁。这种锁升级机制是根据不同的并发度使用不同的加锁方式(这也是 Java 团队对 synchronized 的优化)。

当我们使用 synchronized 关键字时,一般就认为该部分代码会在多线程环境中执行。如果对象从无锁状态一步一步升级会浪费性能。所以,通常 JVM 会开启偏向锁,即对象创建之后 Mark Word 的后三位是 101 而不是 001。

往期推荐

  1. 为什么 MySQL 单表数据量最好别超过 2000w
  2. ConcurrentHashMap 源码分析(一)
  3. IoC 思想简单而深邃
  4. ThreadLocal
  5. JDK 动态代理

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php动态高亮web源代码

php动态高亮web源代码 注:配置好不允许高亮的文件名,安全第一 #php实现动态展示目录树结构源代码 适用于开放源代码,结合html缓存使用效果更佳,因循环较多不适合放首页 能力有限没实现行号 效果截图 代码 4个文件放统一目录…

大数据分析与应用实验(黑龙江大学)

实验一 Hadoop伪分布式实验环境搭建与WordCount程序 一、实验目的 1、学习搭建Hadoop伪分布式实验环境 2、在伪分布式实验环境下运行WordCount程序 二、实验内容 1、搭建Hadoop伪分布式实验环境,并安装Eclipse。 2、在Eclipse环境下,编写并执行Wor…

怎样选购内衣洗衣机?2024年5款最新推荐机型种草

随着科技的不断发展,内衣洗衣机成为了家家户户必备的小家电之一,为我们的生活带来了极大的便利。但面对市场上众多的内衣洗衣机品牌,如何选择一款质量好的内衣洗衣机呢?本文将为您推荐5款最新的内衣洗衣机品牌,从而帮助…

【C++】C++中的构造函数和析构函数详解

欢迎来到CILMY23的博客 本篇主题为:C中的构造函数和析构函数详解 个人主页:CILMY23-CSDN博客 系列专栏:Python | C | C语言 | 数据结构与算法 感谢观看,支持的可以给个一键三连,点赞关注收藏。 写在前头&#xff1…

GaN HEMT中短沟道效应的建模

来源:Modeling of Short-Channel Effects in GaN HEMTs(TED 20年) 摘要 在本文中,我们提出了一种用于估算GaN高电子迁移率晶体管(HEMT)器件中短沟道效应(SCEs)的显式和解析的基于电…

手搓单链表(无哨兵位)(C语言)

目录 SLT.h SLT.c SLTtest.c 测试示例 单链表优劣分析 SLT.h #pragma once#include <stdio.h> #include <assert.h> #include <stdlib.h>typedef int SLTDataType;typedef struct SListNode {SLTDataType data;struct SListNode* next; }SLTNode;//打印…

vue2项目升级到vue3经历分享1

依据vue官方文档&#xff0c;vue2在2023年12月31日终止维护。因此决定将原来的岁月云记账升级到vue3&#xff0c;预计工作量有点大&#xff0c;于是想着把过程记录下来。 原系统使用的技术栈 "dependencies": {"axios": "^0.21.1","babel-…

springboot+vue新疆肉牛智慧牧场养殖系统

系统涉及的对象是奶牛。 系统使用员工有管理员和普通员工。 管理员有修改的权限&#xff0c;普通员工没有。 系统需要包含奶牛的编号&#xff0c;种类&#xff0c;体重&#xff0c;健康情况、生长情况、牛奶产量&#xff0c;以及上次更新数据时间等信息&#xff0c;管理员可以对…

回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测

回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测 目录 回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现SSA-ESN基于麻雀搜索算法…

深圳证券交易所Binary行情数据接口规范

对接深圳证券交易所Binary行情数据接口其实并不难&#xff0c;你需要具备以下知识。 1、需要了解Binary报文设计结构&#xff0c;消息头消息体消息尾。 消息体&#xff1a; 如果是纯map结构的比较简单&#xff0c;字段平铺开来即可。如{"id":"1","…

JEECG/SpringBoot集成flowable流程框架

IDEA安装Flowable BPMN visualizer插件 pom.xml中引入flowable相关依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><depe…

盘点数据资产管理十大活动职能 优化企业数据资产管理和应用

在当今的数字化时代&#xff0c;数据已成为企业最宝贵的资产之一&#xff0c;在上篇文章中我们对数据资产管理进行了初步的介绍。 上篇文章指路&#x1f449;什么是数据资产管理&#xff1f;详谈数据资产管理的难点与发展现状&#xff01; 有效的数据资产管理不仅能提升企业的…