synchronized的锁升级过程和详细的代码演示

synchronized锁升级过程详解 注:synchronized锁流程如下 第一步,检查MarkWord里面是不是放的自己的ThreadId ,如果是,表示当前线程是处于 “偏向锁” 第二步,如果MarkWord不是自己的ThreadId,锁升级,这时候,用CAS来执行切换,新的线程根据MarkWord里面现有的ThreadId,通知之前线程暂停,之前线程将Markword的内容置为空。 第三步,两个线程都把对象的HashCode复制到自己新建的用于存储锁的记录空间,接着开始通过CAS操作,把共享对象的MarKword的内容修改为自己新建.. 阅读详情

在了解这个知识之前先了解Java对象的内容布局

一、锁升级的过程

在JDK1.0、1.2synchronized就是一个重量级的锁,效率不高,后来JDK对synchronized做了优化,在上锁的时候有一个锁升级的过程,
偏向锁-》轻量级锁(无锁,自旋锁、自适应自旋)-》重量级锁
如果大家不理解以上锁的类型可以看这篇文章重量级锁、自旋锁、轻量级锁、偏向锁、悲观、乐观锁等各种锁(转)

  1. 偏向锁:顾名思义就是偏向于第一个访问的线程。也就是说在无竞争的环境下,第一个线程访问的同步代码块,那么就会,会采用CAS机制,把这个同步代码块标记为有人在执行了并把这个线程ID写到锁对象的MarkWord中,这个锁就会偏向这个线程,下次有线程访问的时候就会判断是否有人在执行了,并且线程的ID是是之前访问过的线程访问,那么他就会直接进进入同步代码块中并执行,这样就会少一次cas的开销。偏向锁会有一个延迟,程序刚启动的大约三四秒内不会出现偏向锁。 解决方法有两个:
    (1)加sleep 5s再试
    (2)-XX:BiasedLockingStartupDelay=0 关闭关闭延迟开启偏向锁,JDK6默认开启偏向锁
    计算过hashcode值的对象不会加偏向锁,因为对象头没有空间放线程id了。
  2. 轻量级锁:轻量级锁体现轻量的点就在于自旋。当有任意的一个线程与持有偏向锁的线程进行资源竞争,那么锁就会升级成轻量级锁。每个线程的线程栈中都有一个lock record对象,哪个线程把自己的lock record的指针记录在锁对象头中,哪个线程就持有轻量级,抢的方式就是自旋(CAS)。如果自旋一定的次数还没拿到锁,jdk1.6之前默认有的线程自旋超过10次或者在那自旋等着的线程数超过整个cpu核数的二分之一,那么锁就会升级成重量级锁。jdk1.6之后加入了自适应自旋,自旋次数JVM自己控制。
  3. 重量级锁:jvm层面的两个标识,加锁解锁都会阻塞其他线程。

二、synchronized加锁的锁状态在markword中的布局

在这里插入图片描述
(1)无锁状态

public class NoLock {
    private static Object o = new Object();
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

在这里插入图片描述
问:可能有人问了,为什么上面图中锁状态最后两位表示锁标记位而打印出来的是前面的两位?
答:这就涉及到了大端模式和小端模式了,大端模式是高位字节存储在底地址段,低位字节存储在高地址段,小端模式是低位字节存储在底地址段,高位字节存储在高地址段,如:

0x 00 00 00 00 00 00 00 01 表示MarkWord的8个字节,最左边就是高位字节,最右边就是地位字节
小端模式在内存中存储顺序:
0x 01 00 00 00 00 00 00 00
大端模式在内存中存储顺序:
0x 00 00 00 00 00 00 00 01 

大家实在不懂的可以看一下这篇文章字节序–大端模式和小端模式

问:分代年龄最多可以改到多少?
答:我们从上图可以看到分代年龄(就是一个对象被垃圾回收多少次就会被移到老年代)占4bit,所以网上很多人说把分代年龄改成30多,20多来防止老年代被快速填满是错误的,因为4bit最大是15,所以分代年龄最大可以被调到15次。

如果锁对象在无锁状态下调用hashcode方法,MardWord中会存储hashcode的信息:

public class NoLock {
    private static Object o = new Object();
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        o.hashCode();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

在这里插入图片描述

(2)偏向锁状态

public class DeflectionLock {
    private static Object o = new Object();
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        lock();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
    private static void lock() {
        synchronized (o) {

        }
    }
}

在这里插入图片描述
问:根据上面我们的分析,应该出现偏向锁的,为什么没有出现呢?
答:偏向锁会有一个延迟,程序刚启动的三四秒内不会出现偏向锁

public class DeflectionLock {
    private static Object o;

    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        lock();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

    private static void lock() {
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

在这里插入图片描述
问:为什么全局静态锁对象o要在mian方法里面初始化而不是在创建的时候初始化,而且还没进入到同步代码块中,相应的锁状态就已经是偏向锁了?
答:jdk6默认开启偏向锁,但是是输入延时开启,也就是说,程序刚启动创建的对象是不会开启偏向锁的,几秒后后创建的对象才会开启偏向锁的。当类加载器将类加载到JVM中的时候就会创建静态变量,及对象是不会开启偏向锁。而且我们可以看到当加完偏向锁后,MardWord中的线程ID是不为空的。

public class DeflectionLock {
    private static Object o;

    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        o = new Object();
        o.hashCode();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        lock();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

    private static void lock() {
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

在这里插入图片描述
我们可以看到 计算过hashcode值的对象不会加偏向锁,而是直接加了轻量级锁。

(3)轻量级锁

public class LightweightLocking {
    private static Object o;
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000L);
        o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        new Thread(LightweightLocking::lock).start();
        // 加个睡眠是怕上面的线程没有执行完成而形成线程争用而升级为重量级锁
        Thread.sleep(3000L);
        lock();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

    private static void lock() {
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在第一个线程获取到偏向锁并把自己的线程ID写到锁对象的MarkWord中,当主线程进入同步代码块发现不是自己的线程ID,锁就升级到了轻量级锁,这里我只是简单的来说,其实还是很复杂的,过程大家可以看下面的这张图,或者看这篇作者的文章偏向锁。退出synchronized代码块之后又会变成无锁的状态,因为轻量级锁会有一个锁撤销的过程
在这里插入图片描述
(4)重量级锁

public class HeavyweightLock {
    private static Object o;
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000L);
        o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        new Thread(HeavyweightLock::lock).start();
        lock();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

    private static void lock() {
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

在这里插入图片描述
在这里插入图片描述

以上就是synchronized的锁升级的详细过程,如果大家感觉有所收获的话,麻烦素质三连哈~

【Synchronized锁原理以及升级过程】 Synchronized 中对象头MarkWord的深入理解 阅读详情

相关推荐

Arduino Nano + MCP3422A0 ADC 毫欧表:3档分辨率(0.1mΩ-1.3kΩ)开尔文连接实测

本文详细介绍了如何使用Arduino Nano与MCP3422A0 ADC构建高精度毫欧表,采用四线制开尔文连接和三档量程设计,实现0.1mΩ-1.3kΩ的精确测量。通过精密恒流源和18位ADC技术,结合智能量程切换和数字滤波算法,显著提升测量精度和稳定性,适用于电子维修、PCB测试等场景。

weixin_28292761的博客 325

synchronized锁升级过程

从理论到实操,详细介绍了锁的底层升级过程并用代码进行验证,加深记忆

在路上 1万+

实战拆解:RAG vs Agent在金融风控中的性能对比

2024年上半年我帮某华东地区城商行做零售交易反欺诈系统升级时,技术团队曾发生过一次激烈争论:一派认为应该优先上RAG(检索增强生成)方案,成本低、落地快、合规性好;另一派坚持要上Agent(智能体)方案,推理能力强、能应对复杂新型欺诈。最终我们做了完整的AB测试,结论是两者没有绝对的优劣,只有场景适配的差异:RAG适合高并发、低时延的实时风控场景,Agent适合低并发、高准确率要求的事后核查/大额审批场景,两者结合的 hybrid 方案能覆盖95%以上的风控需求。本文我会结合真实项目的测试数据,从核心概念

AI天才研究院 251

Synchronized的锁升级过程是怎样的?

关键字加到static静态方法和代码块上都是是给 Class 类上锁;关键字加到实例方法上是给对象实例上锁;尽量不要使用,因为 JVM 中,字符串常量池具有缓存功能,多个线程使用相同的字符串值,实际使用的是同一个对象。

weixin_45102820的博客 4523

无人机WIFI集群组网技术详解及成本分析

无人机WIFI集群组网技术是指利用无人机作为移动平台,通过集成高性能的WIFI模块,实现多架无人机之间以及无人机与地面控制站之间的无线通信组网。在协议层面,无人机WIFI集群组网需要遵循标准的无线通信协议,如IEEE 802.11系列(即WIFI标准),同时可能还需定制或优化路由协议、媒体访问控制(MAC)协议等,以确保高效、可靠的数据传输。数据安全与隐私保护:无人机集群组网中传输的数据可能涉及敏感信息,需采取加密、认证等安全措施,确保数据传输的安全性和用户隐私的保护。根据性能不同,价格差异较大。

专注多旋翼、复合翼无人机技术研究,从事低空经济行业。 1584

树莓派视觉小车实战:OpenCV驱动的智能物体追踪系统

本文详细介绍了如何从零开始构建一个基于树莓派的智能视觉小车,实现物体跟踪功能。通过OpenCV进行图像处理,结合颜色与轮廓识别算法,让小车能够实时锁定并追踪特定目标。内容涵盖硬件搭建、软件环境配置、核心代码解析及运动控制逻辑,为创客和开发者提供了完整的实战指南。

weixin_29047545的博客 144

synchronized锁是如何升级的

synchronized锁升过程:偏向锁-》轻量级锁-》重量级锁。

天然玩家的博客 3529

EMC辐射发射测试:垂直与水平极化测试原理与实战指南

电磁兼容(EMC)测试是确保电子设备在复杂电磁环境中稳定运行的关键环节,其核心在于评估设备产生的电磁干扰(EMI)强度。辐射发射测试作为EMC测试的重要组成部分,通过测量设备向空间辐射的电磁噪声,判断其是否符合国际标准限值。测试原理基于电磁波的极化特性,即电场矢量的振动方向,主要分为垂直极化和水平极化。理解极化特性对于精准定位辐射源、高效进行EMC整改具有重要技术价值。在工程实践中,垂直极化噪声通常源于线缆辐射等垂直结构,而水平极化噪声多来自PCB走线等水平结构。通过分别测量两种极化方向的辐射最大值,可以全

weixin_32770423的博客 360

Synchronized锁的升级过程

synchronized锁升级过程依次为无锁、偏向锁、轻量级锁、重量级锁,部分文章认为synchronized锁不存在降级过程,但在openjdk的hotsopt jdk8u里是有锁降级的机制的。 对象头 锁升级示意图 1. 无锁到偏向锁 线程A执行到同步代码块时,检查对象头锁标志位是否为01,再看偏向锁标志位是否为0(即检查对象是否为无锁状态),通过CAS操作尝试修改MarkWord字段,这里CAS操作只尝试一次,失败的话说明发生锁竞争,立即升级为轻量级锁。成功修改后执行同步代码块,执行完毕后不主动释

举个锤子的博客 4741

华为OD机试真题 新系统 - 勇攀数字高峰 (Java/Py/C/C++/Js/Go)

本文整理华为 OD 机试新系统机考真题库,涵盖高频考点精析与完整题目内容,提供 C 语言、Java、C++、Python、Go、JavaScript 多语言源码实现,搭配详细解题思路讲解,并支持在线 OJ 刷题练习,助力高效备考华为 OD 机试新系统。

算法大师! 2097

【python数据挖掘课程】二十八.基于LDA和pyLDAvis的主题挖掘及可视化分析

这是《Python数据挖掘课程》系列文章,前面很多文章都讲解了数据挖掘、机器学习,这篇文章主要讲解LDA和pyLDAvis算法,同时讲解如何读取CSV文本内容进行主题挖掘及可视化展示。文章比较基础,希望对你有所帮助,提供些思路,也是自己教学的内容。推荐大家购买作者新书《Python网络数据爬取及分析从入门到精通(分析篇)》,如果文章中存在错误或不足之处,还请海涵。 目录: 一.显示结果及安装 二.LDA主题挖掘 三.pyLDAvis可视化分析 四.小结

杨秀璋的专栏 1万+

Synchronized锁升级

于是引入了偏向锁,偏向锁在获取资源的时候会在资源对象上记录该对象是偏向该线程的,偏向锁并不会主动释放,这样每次偏向锁进入的时候都会判断该资源是否是偏向自己的,如果是偏向自己的则不需要进行额外的操作,直接可以进入同步操作。在1.6之前,锁都是重量级锁,即我们不管什么线程来操作资源,都要进行加锁释放锁,如果有多线程,还要等待之类的,很浪费资源,1.6之后引入了偏向锁与轻量锁来减小获取和释放锁所带来的性能消耗。当两个或以上线程交替获取锁,但并没有在对象上并发的获取锁时,偏向锁升级为轻量级锁。

Shenandoah7的博客 1181

华为OD机试真题 新系统2026-04-01 Python&JS 实现【空间占用计算】

员工A的磁盘空间经常被耗尽,他需要找到占用空间最大的目录或文件,然后决定如何清理文件释放空间。给定某一目录,请编写程序帮助他统计该目录内一级子目录和文件的占用空间,并返回目标目录一级子项(文件或子目录)中占用空间最大的项。

MISAYAONE的博客 1309

模拟synchronized锁升级过程(详细代码)

synchronized在1.6之后发生了很大改动,做了很多优化。因为Doug Lea大师的ReentrantLock类设计的很完美,jdk源码作者不服,所以对synchronized做了很大的改动。 此博客针对已对synchronized锁有所了解的。 首先我们需要知道synchronized具有4种锁的状态(细分5种): 无锁无偏向 无锁可偏向 有锁已偏向 轻量锁 重量锁...

a568283992的博客 1017

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

【温故知新】直观看到synchronized的锁升级过程

本文将直观展示synchronized的多个锁升级过程和使用场景。温故知新

scugxl的专栏 302

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

synchronized锁升级示例演示

在说synchronized升级之前,先说明一下java对象的内存布局分为三部分:对象头、实例数据,对齐填充;其中对象头中含有对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志位、线程持有的锁、偏向线程ID等。在不同的锁状态标志位下有不同的差别,如下图所示: 如何查看对象占用内存的情况呢?OpenJDK 提供了一个非常好用的工具,JOL包,其maven依赖如下: <dependency> <groupId>org.openjdk.jol</groupId>

XiaoloveYi的专栏 207

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

java synchronized 锁优化:偏向锁、轻量级锁、重量级锁升级流程

快速回顾:① synchronized 锁会按 “偏向锁→轻量级锁→重量级锁” 按需升级;② 锁优化核心是 “细粒度、短持有、低竞争”;③ 需结合 Java 版本选择锁策略,避免版本适配问题。延伸学习:① JVM 锁优化的底层实现(对象头、监视器锁);② 并发工具(ConcurrentHashMap、原子类)的锁优化机制;③ 虚拟机参数对锁优化的影响。面试备准:1. Q:synchronized 的锁升级流程?A:单线程偏向锁→低竞争轻量级锁(自旋)→高竞争重量级锁(阻塞);2. Q:偏向锁的作用?

m0_67391377的博客 644

【JUC并发编程系列】深入理解Java并发机制:从synchronized到CAS锁升级全过程(三、synchronized 前置知识)

本文深入剖析Java中synchronized关键字的工作原理,涵盖从偏向锁到重量级锁的升级过程,以及重入锁的重要性。通过对比乐观锁与悲观锁,手动实现基于CAS的重入锁,并探讨公平锁与非公平锁的区别。结合实例代码,帮助读者理解不同场景下锁的选择与优化策略。

欢迎来到我的技术空间!我是一名经验丰富的Java开发工程师,热衷于分享我在软件开发领域的知识和心得。在这个博客里,您会发现一系列关于Java编程的文章,包括最佳实践、技术趋势、代码优化技巧以及一些有趣的项目案例。无论是初学者还是有经验的开发者,都能在这里找 1384

synchronized

  1、synchronized的几种基本用法:   https://gitee.com/play-happy/base-project/tree/developer/src/main/java/org/burning/sport/javase/thread/synchronizeds public class SynchronizedTest1 { private...

weixin_30784501的博客 88

Synchronized详细介绍之锁升级过程

Synchronized详细介绍之锁升级过程前言线程与进程的区别进程线程区别协程二级目录三级目录 前言 我们在并发编程过程中,会有一些资源或者操作是必须要进行序列化访问的,就是线程之间不能并发的访问,必须要进行串行访问,所以就引入了锁的概念,java中只用的锁主要有两种,一种是jdk内置的锁,一种是juc包下面的锁,jdk内置的锁是不要释放的,由jvm自动给我们释放锁,而juc包下面的锁是有Doug Lea大神开发的,在编程的时候需要在finally进行锁的释放,否则很容易导致死锁; 线程与进程的区别 谈到

JAVA技术爱好者 3976

深入理解synchronized锁升级过程

1.简介 在Java高并发系统中,我们常常需要使用多线程技术来提高系统的运行速度,而多线程带来的数据安全问题就是我们必须要解决的问题。在Java中,可以使用synchronized关键字来实现多线程并发中的数据安全问题。 这里简单介绍下synchronized的三种用法: 修饰实例方法:以实例对象作为锁,进入同步代码前需要获得当前实例对象的锁 修饰类方法(static修饰的方法):以类对象为锁,进入同步代码块前需要获得当前类对象的锁 修饰代码块:需要指定一个锁对象(既可以是实例对象,也可以是) 即

weixin_40910372的博客 1万+

详细聊聊 Synchronized,以及锁的升级过程

关键字是用于实现线程同步的重要机制,它通过内置锁(Monitor)确保多个线程对共享资源的安全访问。JVM根据线程竞争情况动态调整锁状态,以减少性能开销。字段记录了锁状态信息。Monitor对象(如。

大户影视的博客 1598

synchronized锁升级

synchronized锁升级

weixin_45794641的博客 1万+

synchronized加锁原理以及锁升级过程

由于synchronized中用到了CAS技术,此处先对CAS做个简单介绍。是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败。CAS(V,A,B)操作中至少包含三个操作数——需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。如果内存位置V的值与预期原值A相匹配,那么处理器会自动将该位置值更新为新值B。否则处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。在。

cxbtdd的博客 1787
上一篇: CAS(compare and swap)详解,追溯到HOTSPOT源码
下一篇: (1)ElasticSearch基本概念介绍
suixinghero
博客等级 码龄7年 10粉丝 58原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值