Java synchronized重量级锁实现过程浅析
作者:每天都要进步一点点 发布时间:2023-10-25 14:10:17
一、什么是重量级锁
当有大量的线程都在竞争同一把锁的时候,这个时候加的锁,就是重量级锁。
这个重量级锁其实指的就是JVM内部的ObjectMonitor监视器对象:
ObjectMonitor() {
_header = NULL;//锁对象的原始对象头
_count = 0;//抢占当前锁的线程数量
_waiters = 0,//调用wait方法后等待的线程数量
_recursions = 0;//记录锁重入次数
_object = NULL;
_owner = NULL;//指向持有ObjectMonitor的线程
_WaitSet = NULL;//处于wait状态的线程队列,等待被唤醒
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ;//等待锁的线程队列
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
二、重量级锁的演示
public class HightweightLockDemo02 {
public static void main(String[] args) {
Object objLock = new Object();
new Thread(() -> {
synchronized (objLock) {
System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
}
}, "t1").start();
new Thread(() -> {
synchronized (objLock) {
System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
}
}, "t2").start();
}
}
运行程序:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 1a 33 c9 e1 (00011010 00110011 11001001 11100001) (-506907878)
4 4 (object header) 43 01 00 00 (01000011 00000001 00000000 00000000) (323)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 1a 33 c9 e1 (00011010 00110011 11001001 11100001) (-506907878)
4 4 (object header) 43 01 00 00 (01000011 00000001 00000000 00000000) (323)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可见,当多个线程共同抢占同一把锁的时候,锁对象MarkWord的最后三位是“010”,代表的就是一个重量级锁。
三、重量级锁的原理
以上述代码为例,synchronized获取的锁是重量级锁,synchronized修饰代码块,使用javap -p -v .\HightweightLockDemo02.class指令查看其字节码:
在编译的时候,JVM会在同步块开始位置插入monitorenter指令,在同步块结束位置插入monitorexit指令。当线程执行到monitorenter指令时,会尝试获取对象所对应的Monitor所有权,如果获取成功,则表示获取到了锁,会在Monitor的_owner中存在当前线程的ID,这样它将处于锁定状态,除非退出同步块,否则其他线程无法获取得到这个Monitor。
四、锁的优缺点对比
下表是对各种状态的锁的对比:
锁的类型 | 优点 | 缺点 | 适用场景 |
偏向锁 | 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 | 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 | 适用于只有一个线程访问同步块场景 |
轻量级锁 | 竞争的线程不会阻塞,提高了程序的响应速度 | 如果始终得不到锁竞争的线程,使用自旋会消耗CPU,导致CPU空转 | 追求响应时间 同步块执行速度非常快 |
重量级锁 | 线程竞争不使用自旋,不会消耗CPU | 线程阻塞,响应时间缓慢 | 追求吞吐量 同步块执行时间较长 |
来源:https://weishihuai.blog.csdn.net/article/details/126536742


猜你喜欢
- 本文实例为大家分享了SpringMVC按Ctrl上传多个文件的具体实现代码,供大家参考,具体内容如下JSP页面注意:必须加入multiple
- 实现效果:注意:using system.io; 往Form1上添加控件picturebox,再添加imagelist,并设置imageli
- 一般在web应用中,对客户端提交上来的图片肯定需要进行压缩的。尤其是比较大的图片,如果不经过压缩会导致页面变的很大,打开速度比较慢,当然了如
- 一、ThreadPoolThreadPool是.Net Framework 2.0版本中出现的。ThreadPool出现的背景:Thread
- 前言我们都知道memberwiseclone 会将浅克隆。什么是浅克隆?如何深克隆呢?正文public class good{
- 1.RecycledPool的重用场景以及使用:多个RecyclerView出现,并且他们的item布局结构一致,这时候可以进行重用。在进行
- 末日这天写篇博客吧,既然没来,那就纪念一下。这次谈谈自制控件,也就是自定义控件,先上图,再说1.扩展OpenFileDialog,在Open
- 现在有很多库、实用工具和程序任Java开发人员选择。每个工具都有其优点,但其中有一些因它的知名度、多功能性和有效性从众多选项中脱颖而出。以下
- 图片解析:1.生成字节码文件的过程可能产生编译时异常(checked),由字节码文件到在内存中加载、运行类此过程可能产生运行时异常(unch
- 1. Dubbo是什么?Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,
- 本文实例为大家分享了Android实现录制按钮的具体代码,供大家参考,具体内容如下初始化布局文件中参数private void initPa
- 本文实例讲述了Java基于socket实现的客户端和服务端通信功能。分享给大家供大家参考,具体如下:以下代码参考马士兵的聊天项目,先运行Ch
- 一:简述如果我们想要生成一个随机数,通常会使用Random类。但是在并 * 况下Random生成随机数的性能并不是很理想,今天给大家介绍一下J
- RecyclerView是Android 5.0新增的控件,在android-support-v7下面。官方文档对RecycleView介绍
- 1.封装分页Page类package com.framework.common.page.impl;import java.io.Seria
- 最近碰到一个大转盘的业务,奖品可根据数据后台灵活设置中奖概率,看起来挺简单的业务功能,但实现起来对我这个毫无经验的人来说并不容易,后面又碰到
- 为了提升编译速度,这几天用上了 AS 3.0 和 Gradle 3.0 插件,不得不说不论是 AS 3.0,还是 Gradle 3.0 都变
- PagerBottomTabStrip 是一个基本按谷歌Material Design规范完成的安卓底部导航栏控件官方设计规范:https:
- 1、在POM.xml文件下添加如下代码;注意:version、configuration、executions三个标签是我后来查找添加的,网
- 根据约定,在使用java编程的时候应尽可能的使用现有的类库,当然你也可以自己编写一个排序的方法,或者框架,但是有几个人能写得比JDK里的还要