Code Ease Code Ease
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档

神秘的鱼仔

你会累是因为你在走上坡路
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档
服务器
  • Java核心基础

    • 基础篇

    • 集合类

    • JVM虚拟机

    • Java并发

      • 产品经理问我:手动创建线程不香吗,为什么非要用线程池呢?
      • 面试官:我问的是Java内存模型,你回答堆栈方法区干嘛?
      • 指令重排序、内存屏障很难?看完这篇你就懂了!
      • Volatile只会用不知道原理?一篇文章带你深究volatile
      • 有关synchronized锁的知识点,我用一篇文章总结了
        • 面试被问AQS、ReentrantLock答不出来?这些知识点让我和面试官聊了半小时!
        • 大厂面试题:你知道JUC中的Semaphore、CyclicBarrier、CountDownLatch吗
        • 关于ThreadLocal的九个知识点,看完别再说不懂了!
    • 框架的艺术

    • 分布式与微服务

    • 开发经验大全

    • 版本新特性

    • Java
    • Java核心基础
    • Java并发
    CodeEase
    2023-09-19
    目录

    有关synchronized锁的知识点,我用一篇文章总结了

    作者:鱼仔
    博客首页: codeease.top (opens new window)
    公众号:Java鱼仔

    关于Java多线程锁的升级原理,这篇文章会让你另有收获

    # 2.1 Java对象内存布局

    在了解锁升级原理之前我们首先要了解一下Java对象在内存中的布局

    5-1.png

    对象头用于存储对象的元数据信息,包括运行时数据和类型指针、实例数据存储的是真正有效数据、对齐填充主要补充字节,使得内存所占字节能被8整除。

    其中对象头Header占12个字节:Mark Word占8个字节,类型指针class pointer占4个字节(默认经过了压缩,如果不开启压缩占8个字节)

    实例对象按实际存储有不同大小,对象为空时等于0。

    Padding表示对齐,当此时内存所占字节不能被8整除时补上相应字节数。

    # 2.2 synchronized锁升级

    Java中锁升级的最佳实例就是synchronized,之所以要讲上面的内存布局,是因为synchronized把锁信息存放在对象头的MarkWord中。

    在早期的jdk版本中,synchronized是一个重量级锁,保证线程的安全但是效率很低。后来对synchronized进行了优化,有了一个锁升级的过程:

    无锁态(new)-->偏向锁-->轻量级锁(自旋锁)-->重量级锁

    通过MarkWord中的8个字节也就是64位来记录锁信息。

    锁升级过程详解: 当给一个对象增加synchronized锁之后,相当于上了一个偏向锁。

    当有一个线程去请求时,就把这个对象MarkWord的ID改为当前线程指针ID(JavaThread),只允许这一个线程去请求对象。

    当有其他线程也去请求时,就把锁升级为轻量级锁。每个线程在自己的线程栈中生成LockRecord,用CAS自旋操作将请求对象MarkWordID改为自己的LockRecord,成功的线程请求到了该对象,未成功的对象继续自旋。

    如果竞争加剧,当有线程自旋超过一定次数时(在JDK1.6之后,这个自旋次数由JVM自己控制),就将轻量级锁升级为重量级锁,线程挂起,进入等待队列,等待操作系统的调度。

    # 2.3 锁消除

    说了锁升级过程,有必要说一下说一下锁消除和锁粗化。

    在某些情况下,如果JVM认为不需要锁,会自动消除锁,比如下面这段代码:

    public void add(String a,String b){
        StringBuffer sb=new StringBuffer();
        sb.append(a).append(b);
    }
    
    1
    2
    3
    4

    StringBuffer是线程安全的,但是在这个add方法中stringbuffer是不能共享的资源,因此加锁只会徒增性能消耗,JVM就会消除StringBuffer内部的锁。

    # 2.4 锁粗化

    在某些情况下,JVM检测到一连串的操作都在对同一个对象不断加锁,就会将这个锁加到这一连串操作的外部,比如:

    StringBuffer sb=new StringBuffer();
    while(i<100){
        sb.append(str);
        i++;
    }
    
    1
    2
    3
    4
    5

    上述操作StringBuffer每次添加数据都要加锁和解锁,连续100次,这时候JVM就会将锁加到更外层(while)部分。

    上次更新: 2025/04/29, 17:22:06
    Volatile只会用不知道原理?一篇文章带你深究volatile
    面试被问AQS、ReentrantLock答不出来?这些知识点让我和面试官聊了半小时!

    ← Volatile只会用不知道原理?一篇文章带你深究volatile 面试被问AQS、ReentrantLock答不出来?这些知识点让我和面试官聊了半小时!→

    最近更新
    01
    AI大模型部署指南
    02-18
    02
    半个月了,DeepSeek为什么还是服务不可用
    02-13
    03
    Python3.9及3.10安装文档
    01-23
    更多文章>
    Theme by Vdoing | Copyright © 2023-2025 备案图标 浙公网安备33021202002405 | 浙ICP备2023040452号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式