Java中锁的深入理解

news2024/9/24 18:15:46

目录

对象头的理解

Monitor(锁)

锁类型

偏向锁

偏向锁的优化机制

轻量级锁

重量级锁


对象头的理解

在32位Java虚拟机中普通对象的对象头是占用8个字节,其中4个字节为Mark Word。用来存储对象的哈希值,对象创建后在JVM中的生命(经历GC回收后存活次数)等信息。另外四个字节为Klass Word用来存储对象类型,是String还是Student又或是Teacher。

Mark Word的存储结构为

Monitor(锁)

Monitor锁结构如下

这三个区域分别代表

  1. WaitSet:线程通过wait()方法进入的阻塞状态,从Owner进入WaitSet集合,通过notify()方法唤醒后进入EntryList。
  2. EntryList:阻塞线程集合,需要通过非公平竞争去获取锁
  3. Owner:存储当前获取锁的线程。

当一个对象被加入重量级锁时,Mark Word会存储Monitor的地址。

锁类型

均针对于synchronized来进行辨析

偏向锁

偏向锁CPU损耗是最小的一种,在这种锁状态下,系统会认为这个锁通常只会由一个线程独占。默认情况下是开启的,对于本就是需要多线程争抢的对象来说,可以选择禁用偏向锁。

轻量级锁每次都会进行CAS操作,这也会消耗CPU资源,因此,偏向锁采用的是对象中的Mark Word存储的是线程ID。每次加锁时,先判断对象中的Mark Word是否是本线程ID(轻量级锁和偏向锁的锁对象Mark Word存储的信息不同,轻量级锁存储的是对象的hash值,偏向锁存储的是ThreadID)。

当对象被加入偏向锁后,记录的ThreadID并不会因为解锁而消失,而是继续存储在对象的Mark Word中。如果其他线程获取该对象加锁,会撤销ThreadID,变成轻量级锁

当一个可偏向对象调用hashCode方法后,会关闭偏向锁,用来对象的Mark Word用来存储该对象的hash值。

偏向锁的优化机制

批量重偏向:当可偏向对象因为被多个线程访问导致的撤销偏向锁次数过多时(默认值为20),后续的可偏向对象就不会再次进行撤销偏向锁了,因为撤销偏向锁也是需要CPU资源的。而是进行重偏向,JVM会认为初始偏向时,偏向错了,将后续的可偏向对象中的Mark Word修改为现在正在执行的ThreadID,已经被撤销偏向锁的对象则无法恢复。

批量撤销:当偏向锁被撤销次数过多时(默认为40次),JVM会认为,就不应该开启偏向锁,此后创建的每一个对象都是不可偏向的。

轻量级锁

在这种锁状态下,通常应用是一个对象虽然会被多个线程访问,但是多个线程的访问是错开时间的,并不存在竞争关系。

static final Object obj = new Object(); 
public static void method1(){
	synchronized(obj){
        method2();
    }
}

public static void method2(){
	synchronized(obj){
    }
}

首先这是一个线程执行,那么在执行method1时,栈帧中会创建一个Lock Record(锁记录)。里面存储对象的引用地址以及存储锁对象的Mark Word。

如下图所示

接着进行下一步,Object reference指向锁对象,并尝试通过cas交换锁对象的Mark Word。

如下图所示

如果cas成功,那么对象的对象头Mark Word存储的是锁记录的地址以及其状态,表示对该对象进行加锁

如果cas失败,则要分情况看待:

  • 一种是,该对象已经被其他线程上锁,这时说明该对象存在竞争情况,进入锁膨胀状态
  • 一种是,该对象已经被该线程上锁,这属于锁重入,再加入一条Lock Record作为重入计数。

对于第二种情况进行分析。在进行method1时,又进行了method2,此时,会cas失败。但是并不影响。

进行解锁时,取出的锁记录为null时,说明存在重入,此时重入计数-1。

如果取出的锁记录不为null,说明该线程已经不对该对象上锁了,进行真正的解锁操作,通过cas将对象的原有Mark Word恢复给该对象。如果成功的话说明解锁成功,如果cas失败说明进行了锁膨胀升级到了重量级锁,此时去执行重量级锁解锁流程。

重量级锁

最耗费CPU资源的加锁方式。

当线程0已经为对象加上了轻量级锁后,线程1再次对该对象加入轻量级锁,此时CAS失败,那么线程1会为该对象申请Monitor锁。然后自己进入Monitor锁中的EntryList

申请Monitor锁后,会将其地址存储在该对象的Mark Word中。

当线程0进行解锁操作时,会发现CAS解锁失败,此时会进入重量级解锁流程,即通过Monitor地址,找到Monitor锁后,将Owner设置为null,唤醒EntryList中的阻塞线程。


自旋优化:当线程加锁时发现锁被占用会进入阻塞状态,但是这样会大量进行线程上下文切换,比较占用CPU,因此可以使用自旋优化,所谓自旋优化,是线程循环获取锁,失败后还是要去获取锁,如果在规定次数内还没有获取到锁,那么进入阻塞状态,因为这是一个循环过程,也是要占用CPU资源的。注意:单核CPU没有自旋的必要。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Polygon zkEVM协议治理、升级及其流程

1. 引言 随着Polygon社区开发者和内部团队的测试深入,当前版本的Polygon zkEVM不可避免地需更新和某些升级。 为激励开发者对Polygon zkEVM做battle-test,已启动了bug-bounty: Rewards by Threat Level 由于zk-Rollup生态系统还处于萌芽阶…

python 的 import 机制

引言 对于初学 python,或多或少在 import 一个 module 时遇到过 ImportError: attempted relative import with no known parent package 这样的错误信息。对于初学 python,遇到这样的问题是因为在执行 python xxx.py 程序时,xxx.py 程序中 …

〖大前端 - 基础入门三大核心之JS篇㊳〗- DOM访问元素节点

说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费,如需要项目实战或者是体系化资源,文末名片加V!作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

基于springboot实现应急救援物资管理系统项目【项目源码】计算机毕业设计

基于springboot实现应急救援物资管理系统演示 JAVA简介 JavaScript是一种网络脚本语言,广泛运用于web应用开发,可以用来添加网页的格式动态效果,该语言不用进行预编译就直接运行,可以直接嵌入HTML语言中,写成js语言&a…

Centos7 重置 Root 密码

Centos7 重置 Root 密码 1.启动服务器2.编辑启动项3.修改密码4.重新登陆 1.启动服务器 启动服务器后,不要直接进入系统,在开机页面按键盘【E】 2.编辑启动项 按【E】后进入如下页面,并按向下箭头,找到如图位置,添加如…

慢日志查询

概述 MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过 long_query_time 值的SQL,则会被记录到慢查询日志中,ong_query_time 的默认值为 10,意思是运行10S…

JAVA多线程(5)

JAVA多线程(5) 线程安全问题概述 卖票问题分析 单窗口卖票 一个窗口(单线程)卖100张票没有问题 单线程程序是不会出现线程安全问题的 多个窗口卖不同的票 3个窗口一起卖票,卖的票不同,也不会出现问题 多线程程序,没有访问共享数据,不会产生问题 多个窗口卖相同的票 3个窗口…

QT下使用QChart绘制曲线

目录 头文件内容构造函数AddSeries方法UpdateSeries方法AppendSeriesData方法SetLegendVisiableSetRubberBandCPP内容测试函数 需要用到的头文件&#xff1a; #include <QtCharts/QChart> #include <QtCharts/QChartView> #include <QtCharts/QValueAxis> #…

大数据安全 测试

测试1、用户 hive/1.common2.hadoop.fql.comLEXIN.COM 和 nn/1.common2.hadoop.fql.com 分别对 Hive 进行查询 &#xff08;1&#xff09;HDFS 配置 vim /usr/local/fqlhadoop/hadoop/conf/core-site.xml <property><name>hadoop.proxyuser.hive.hosts</name&g…

16. @PostConstruct注解和开关原理(验证码开关、IP开关)

1►PostConstruct注解 PostConstruct是java自带的注解&#xff0c;会在java项目启动的时候先执行下面的方法 2►开关原理&#xff08;验证码开关&#xff09; 我们的项目具有验证码功能&#xff0c;旧版不支持关闭&#xff0c;新版已经支持关闭了。 我们打开页面“参数管…

go-zero微服务的使用

一、入门案例 1、使用goland创建一个工程 2、新建一个user.proto syntax "proto3";package user; // 这个地方表示生成的go的包名叫user option go_package "./user";message UserInfoRequest {int64 userId 1; }message UserInfoResponse {int64 user…

2024年csdn最新最全的Postman接口测试: postman实现参数化

什么时候会用到参数化 比如&#xff1a;一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块&#xff1a;正确的用户名&#xff0c;密码 成功&#xff1b;错误的用户名&#xff0c;正确的密码 失败 postman实现参数化 在实际的接口测试中&#xff0c;部分参数…

【机器学习】特征工程:特征选择、数据降维、PCA

各位同学好&#xff0c;今天我和大家分享一下python机器学习中的特征选择和数据降维。内容有&#xff1a; &#xff08;1&#xff09;过滤选择&#xff1b;&#xff08;2&#xff09;数据降维PCA&#xff1b;&#xff08;3&#xff09;sklearn实现 那我们开始吧。 一个数据集中…

第93步 深度学习图像分割:PSPNet建模

基于WIN10的64位系统演示 一、写在前面 本期&#xff0c;我们继续学习深度学习图像分割系列的另一个模型&#xff0c;PSPNet。 二、PSPNet简介 &#xff08;1&#xff09;金字塔池化模块 (Pyramid Pooling Module) PSPNet的核心是其金字塔池化模块&#xff0c;该模块能够捕…

2024年csdn最新最全面的fiddler教程【1】

Fiddler简介 Fiddler是比较好用的web代理调试工具之一&#xff0c;它能记录并检查所有客户端与服务端的HTTP/HTTPS请求&#xff0c;能够设置断点&#xff0c;篡改及伪造Request/Response的数据&#xff0c;修改hosts&#xff0c;限制网速&#xff0c;http请求性能统计&#xff…

ERR:Navicat连接Sql Server报错

错误信息&#xff1a;报错&#xff1a;未发现数据源名称并且未指定默认驱动程序。 原因&#xff1a;Navicat没有安装Sqlserver驱动。 解决方案&#xff1a;在Navicat安装目录下找到sqlncli_x64.msi安装即可。 一键安装即可。 Navicat链接SQL Server配置 - MarchXD - 博客园 …

【腾讯云 HAI域探秘】——即时职场生存指南小游戏以及【自行搭建Stable Diffusion图片AI绘制 | ChatGLM2-6B AI进行智能对话 | Pytorch2.0 AI框架视频处理】

利用HAI的ChatGLM2 6B做一个即时对话小游戏 ChatGLM2-6B 是开源中英双语对话模型 ChatGLM-6B 的第二代版本&#xff0c;在保留了初代模型对话流畅、部署门槛较低等众多优秀特性的基础之上&#xff0c;ChatGLM2-6B 引入了更强大的性能、更长的上下文、更高效的推理&#xff0c;…

论文阅读——DiffusionDet

在目标检测上使用扩散模型 前向过程&#xff1a;真实框-->随机框 后向过程&#xff1a;随机框-->真实框 前向过程&#xff1a; 一般一张图片真实框的数目不同&#xff0c;填补到同一的N个框&#xff0c;填补方法可以是重复真实框&#xff0c;填补和图片大小一样的框&a…

Linux操作文件的底层系统调用

目录 1.概述 2.open的介绍 3.write 的介绍 4.read 5.close的介绍 6.文件描述符 1.概述 C语言操作文件的几个库函数:fopen,fread,fwrite,fclose; 系统调用:open,read,write,close; 系统调用方法实现在内核中;(陷入内核,切换到内核) 2.open的介绍 open重载:两个参数用于打…

SpringSecurity6 | 默认登录页

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…