Java中锁的深入理解

目录

对象头的理解

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没有自旋的必要。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【顺序表的实现】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1. 数据结构相关概念 1、什么是数据结构 2、为什么需要数据结构? 2、顺序表 1、顺序表的概念及结构 1.1 线性表 2、顺序表分类 3、动态顺序表的实现 总…

ssm+vue的高校疫情防控管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频: ssmvue的高校疫情防控管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结…

【C++入门】拷贝构造运算符重载

目录 1. 拷贝构造函数 1.1 概念 1.2 特征 1.3 常用场景 2. 赋值运算符重载 2.1 运算符重载 2.2 特征 2.3 赋值运算符 前言 拷贝构造和运算符重载是面向对象编程中至关重要的部分,它们C编程中的一个核心领域,本期我详细的介绍拷贝构造和运算符重载。 1. …

面向对象与面向过程的区别

面向对象 以对象为中心,把数据封装成为一个整体,其他数据无法直接修改它的数据,将问题分解成不同对象,然后给予对象相应的属性和行为。 面向过程 关注代码过程,直接一程序来处理数据,各模块之间有调用与…

OSI参考模型

目录 一. OSI参考模型的各层功能二. 网络排错三. 网络安全四. 实体、协议、服务和服务访问点SAP五. TCP IP体系结构 一. OSI参考模型的各层功能 \quad \quad \quad \quad 我们首先来看应用层实现的功能 每个字段的各种取值所代表的意思 \quad \quad 比如要保存的文件内容是ab…

OpenAI 董事会与 Sam Altman 讨论重返 CEO 岗位事宜

The Verge 援引多位知情人士消息称,OpenAI 董事会正在与 Sam Altman 讨论他重新担任首席执行官的可能性。 有一位知情人士表示,Altman 对于回归公司一事的态度暧昧,尤其是在他没有任何提前通知的情况下被解雇后。他希望对公司的治理模式进行重…

【开源】基于Vue.js的高校实验室管理系统的设计和实现

项目编号: S 015 ,文末获取源码。 \color{red}{项目编号:S015,文末获取源码。} 项目编号:S015,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

Tomcat无法映射到activiti-app导致activiti无法启动页面

原因之一:JDK版本与Tomcat版本不匹配,jdk8 yyds 我使用的是JDK11,Tomcat是9.0的,都是最新的,但还是不行,最后JDK改为8,tomcat的cmd后台没有报错,activiti-pp也可以正常访问了,很神奇…

鸿蒙应用开发之打包与上架

一、概述 当您开发、调试完HarmonyOS应用/元服务,就可以前往AppGallery Connect申请上架,华为审核通过后,用户即可在华为应用市场获取您的HarmonyOS应用/元服务。 HarmonyOS会通过数字证书与Profile文件等签名信息来保证应用的完整性&#…

数电实验-----实现74LS139芯片扩展为3-8译码器以及应用(Quartus II )

目录 一、74LS139芯片介绍 芯片管脚 芯片功能表 二、2-4译码器扩展为3-8译码器 1.扩展原理 2.电路图连接 3.仿真结果 三、3-8译码器的应用(基于74ls139芯片) 1.三变量表决器 2.奇偶校验电路 一、74LS139芯片介绍 74LS139芯片是属于2-4译码器…

Halcon Solution Guide I basics(0): 导论解析

文章目录 文章专栏前言文章目录翻译文档的说明 结论LOL比赛结局 文章专栏 Halcon开发 前言 今天开始看Halcon的官方文档。由于市面上的教学主要是以基础的语法,算子简单介绍为主。所以我还是得看官方的文本。别的不多说了。有道词英语词典,启动。 还有…

解决WPF项目xaml出现“正在等待IntelliSense完成”的问题

在WPF项目xaml里经常出现“正在等待IntelliSense完成”的场景,如下图: 解决办法 工具–选项

【智能家居】5、主流程设计以及外设框架编写与测试

目录 一、主流程设计 1、工厂模式结构体定义 (1)指令工厂 inputCmd.h (2)外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…

Activiti7工作流

文章目录 一、工作流介绍1.1 概念1.2 适用行业1.3 应用领域1.4 传统实现方式1.5 什么是工作流引擎 二、什么是Activiti7?2.1 概述2.2 Activiti7内部核心机制2.3 BPMN2.4 Activiti如何使用2.4.1 整合Activiti2.4.2 业务流程建模2.4.3 部署业务流程2.4.4 启动流程实例…

大反转!OpenAI董事会辞职,求奥特曼重返OpenAI?「奥特曼24小时流放」大揭秘...

大家好,我是二狗。 想必大家昨天都被Sam Altman被董事会解雇的事情刷屏了。 然而才仅仅过去一天,OpenAI 董事会就反悔了!正和Sam Altman 商量让他重返CEO职位。 这一反转和Altman被炒鱿鱼一样突然,凄凄惨惨真真假假真真&#x…

340条样本就能让GPT-4崩溃,输出有害内容高达95%?OpenAI的安全防护措施再次失效

仅需340个示例微调GPT-4,即可绕过安全限制,让模型说出“枪支改装方法”、“生化武器制作过程”等有害内容? OpenAI的安全防护措施再次失效,攻击的成功率高达95%! 近日,美国顶尖大学UIUC与斯坦福联合对GPT…

python 的 import 机制

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

【心得】基于flask的SSTI个人笔记

目录 计算PIN码 例题1 SSTI的引用链 例题2 SSTI利用条件: 渲染字符串可控,也就说模板的内容可控 我们通过模板 语法 {{ xxx }}相当于变相的执行了服务器上的python代码 利用render_template_string函数参数可控,或者部分可控 render_…

分库分表

分库,分表,分库分表 “只分库“,“只分表“,“既分库又分表" 何时分库 在面对高并发的情况下,数据库连接成为性能瓶颈。当数据QPS过高导致数据库连接数不足时,考虑分库。在读多写少的场景下&#x…

基于Vue+SpringBoot的超市账单管理系统 开源项目

项目编号: S 032 ,文末获取源码。 \color{red}{项目编号:S032,文末获取源码。} 项目编号:S032,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3…