【JVM】synchronized锁升级的过程

目录

如何从无锁状态到偏向锁状态:

偏向锁升级为轻量级锁:

轻量级锁到自旋锁的状态:

自旋锁升级为重量级锁:

下面是自旋锁升级到重量级锁的过程:

重量级锁的特点如下:


synchronized锁分为三种状态——偏向锁、轻量级锁、重量级锁

如何从无锁状态到偏向锁状态:

        当一个线程访问被synchronized修饰的代码块的时候,并获取对象的锁时,会在对象头中的Mark Word中记录该线程的ID,这就叫做偏向锁

        如果对象的Mark Word中的记录的线程ID为0,表示当前没有线程获取锁,则将该线程的ID记录到Mark Word当中,并将对象头指向偏向锁。

偏向锁升级为轻量级锁:

  • 当其他线程尝试获取一个对象的锁的时候,JVM发现对象头指向的线程ID和当前线程ID不一致的时候,会尝试将偏向锁升级为轻量级锁。
  • JVM也会在Mark Word中分配空间存储锁记录(锁记录包含指针、标志位等信息)
  • 然后JVM会使用CAS(Compare and Swap)操作尝试将对象头中的偏向锁替换为指向锁记录的指针,并将线程ID记录到锁记录当中
  • 如果CAS操作成功,表示锁升级成功,当前线程进入临界区指向代码;如果失败,则说明有其他线程竞争,可能进一步升级为重量级锁

轻量级锁到自旋锁的状态:

  1. 初始状态:假设有两个线程A和B,线程A先获取到了对象obj的轻量级锁,并且正在执行临界区代码。
  2. 竞争锁:线程B也想要获取对象obj的锁,但发现轻量级锁已经被线程A获取了,此时线程B会进入自旋锁状态。
  3. 自旋锁等待:线程B进入自旋锁状态后,会进行一定次数的自旋(即循环重试),不断检查轻量级锁的标记是否被线程A释放。
  4. 自旋锁优化:在自旋锁状态下,如果线程A在很短的时间内释放了轻量级锁,线程B可以立即获取到锁而无需进入阻塞状态。这种情况下,自旋锁避免了线程上下文切换的开销,提高了性能。
  5. 自旋锁等待超时:如果线程B在自旋一定次数后仍然无法获取到锁,就会认为竞争激烈,并且有其他线程执行临界区代码的可能性不大。此时,线程B会放弃自旋锁而进入阻塞状态,让出CPU执行权,等待锁释放。
  6. 自旋锁的优势:自旋锁在临界区代码执行时间短、线程竞争不激烈的情况下可以提高性能,因为避免了线程上下文切换。但如果临界区代码执行时间长,或者线程竞争激烈,使用自旋锁可能会浪费CPU资源。

自旋锁升级为重量级锁:

        当一个线程在自旋锁状态下无法获取到锁时,它会升级到重量级锁。重量级锁是一种阻塞锁,它会导致线程进入阻塞状态并释放CPU的执行权。

下面是自旋锁升级到重量级锁的过程:

  1. 自旋锁等待:假设有两个线程A和B,线程A持有了对象obj的自旋锁,并且正在执行临界区代码。线程B尝试获取锁但失败,进入自旋状态。
  2. 自旋锁等待超时:线程B在经过一定次数的自旋后,仍然无法获取到锁。此时,线程B会放弃自旋锁,并将自己挂起,进入阻塞状态。
  3. 锁升级:线程B进入阻塞状态后,JVM会将锁升级为重量级锁。重量级锁的特点是会导致线程进入阻塞状态,并且释放CPU的执行权。
  4. 线程阻塞:线程B被阻塞后,它不会再去尝试获取锁,直到锁被释放。此时,线程B会进入一个等待唤醒的状态。
  5. 锁释放:当线程A执行完临界区代码后,会释放锁。此时,JVM会选择一个阻塞的线程(例如线程B)唤醒,使其重新尝试获取锁。
  6. 线程唤醒:被唤醒的线程(例如线程B)会从阻塞状态中恢复,并且开始重新尝试获取锁。

重量级锁的特点如下:

  • 高开销:使用重量级锁的线程会进入阻塞状态,这样会导致线程上下文切换的开销,影响性能。
  • 公平性:重量级锁通常是公平的,即等待时间最长的线程会被优先唤醒,以保证公平性。
  • 线程阻塞:获取重量级锁失败的线程会进入阻塞状态,不会消耗CPU资源,等待锁的释放。
  • 粒度较大:重量级锁对应整个对象而不是对象的某个部分,因此在多线程竞争情况下,会导致其他线程也无法访问对象。

        需要注意的是,升级到重量级锁的过程并非是一成不变的,具体实现可能会有不同的策略和优化。锁的具体行为和性能表现还取决于

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

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

相关文章

点云从入门到精通技术详解100篇-基于几何特征的三维点云配准

目录 前言 研究现状 基于几何特征的方法 ICP算法及其变体 基于学习的方法

JavaSE【 String 类】(2)(

一、字符串的不可变性 1.String本身不可变 字符串修改 注意:尽量避免直接对 String 类型对象进行修改,因为 String 类是不能修改的,所有的修改都会创建新对象,效率 非常低下。 public static void main(String[] args) {/*** S…

sublime编辑latex 出现参考文献无法编译报错:citation “...” undefined

问题描述 使用sublime编译latex文件时,参考文献按照常规的方式放好,ctrl B 编译的时候,显示找不到参考文献,编译出的pdf文件也没有references: 但是把文件放到overleaf上就可以直接编译出来,说明是本地编…

向量数据库,能让AI再次起飞吗?

9月7-8日,深圳国际会展中心18号馆 来了,来了,腾讯面向产业互联网领域规格最高、规模最大、覆盖最广的年度科技盛会 -——- 腾讯全球数字生态大会。 9 月 7 日,我们将聚焦产业未来发展新趋势,针对云计算、大数据、人工…

滴滴:二季度中国出行营收同比增长57%,6月日均单量超3000万单

9月9日,滴滴在其官网发布2023年第二季度业绩报告,二季度滴滴实现总收入488亿元,同比增长52.6%;归属于滴滴普通股股东的净亏损为3亿元,经调整EBITA亏损1000万元。 分业务来看,二季度滴滴中国出行&#xff0…

Error: Port Library failed to initialize: -86

最近遇到一个很奇怪的错误,这里记录一下,以备以后再次遇到 Error: Port Library failed to initialize: -86 Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.背景是,就是一普…

fastjson漏洞复现

文章目录 启动环境漏洞复现下载bp插件漏洞扫描dnslog测试是否向外请求资源用工具构造rmi服务器 反弹shell 启动环境 到vulhub目录下 cd vulhub/fastjson/1.2.24-rce安装环境并启动: sudo docker-compose up -d && sudo docker-compose up -d启动成功&…

详解TCP/IP的三次握手和四次挥手

文章目录 前言一、TCP/IP协议的三次握手1.1 三次握手流程 二、TCP/IP的四次挥手2.1 四次挥手流程 三、主要字段3.1、标志位(Flags)3.2、序号(sequence number)3.3、确认号(acknowledgement number) 四、状态…

MySQL——事务

一、事务的开始与结束 一个数据库事务由一条或多条sql语句构成,它们形成一个逻辑的工作单元。这些sql语句要么全部执行成功,要么全部执行失败。 1.1.事物的开始 1.对于DDL(create,alter,drop)和DCL&…

使用playright自动下载vscode已安装插件

import os import re import subprocess import traceback from playwright.sync_api import Playwright, sync_playwright, expect# 执行CMD命令 cmd_command = "code --list-extensions" # 获取已安装扩展列表 process = subprocess.Popen(cmd_command, stdout=su…

Java 中如何实现序列化?

什么是序列化?Java 中如何实现序列化? 在 Java 编程中,序列化是一种将对象转换为字节流的过程,可以将对象在网络中传输或者保存到磁盘中。序列化可以将对象的状态保存下来,以便在需要时重新创建对象。Java 中提供了一…

Android 10.0 禁用adb shell input输入功能

1.前言 在10.0的产品开发中,在进行一些定制开发中,对于一些adb shell功能需要通过属性来控制禁止使用input 等输入功能,比如adb shell input keyevent 响应输入事件等,所以就需要 熟悉adb shell input的输入事件流程,然后来禁用adb shell input的输入事件功能,接下来分…

【数据结构--顺序表】移除元素

题目描述&#xff1a; 代码实现&#xff1a; 1、指针实现 int removeElement(int* nums, int numsSize, int val) {int* dst nums, * src nums;int n1 0,n20;while (n1n2 < numsSize){if (*src ! val){*dst *src;dst;src;n1;//表示src走的步数}else{src;n2;//表示src走…

【C++心愿便利店】No.5---构造函数和析构函数

文章目录 前言一、类的6个默认成员函数二、构造函数三、析构函数 前言 &#x1f467;个人主页&#xff1a;小沈YO. &#x1f61a;小编介绍&#xff1a;欢迎来到我的乱七八糟小星球&#x1f31d; &#x1f4cb;专栏&#xff1a;C 心愿便利店 &#x1f511;本章内容&#xff1a;类…

GO远程构建并调试

GO远程调试 之前写C&#xff0c;一直习惯了本地IDERemote CMake/GDB编译调试的模式。 因为6.824课程需要用GO&#xff0c;好像没有特别好的支持。记录一下如何配置调试的。 IDE: Goland 操作系统&#xff1a;Windows 远程服务器&#xff1a;Ubuntu 首先配置SSH,让其可以连接到…

typeScript--[es6class类实现继承]

一.js中实现继承 // js实现继承 // 父类 function Father(name) {this.name namethis.say function () {console.log(this.name "在唱歌")} } var f new Father("逍遥的码农")// 子类 function Son(name) {Father.call(this, name) } Son.prototype …

source insight keil 中文乱码

1. 乱码的根本原因就是编码的方式太多了&#xff0c;你用这种编码&#xff0c;他用那种编码&#xff0c;就变成鸡同鸭讲了&#xff0c;对牛弹琴就要用牛语&#xff0c;如果全世界只有一种编码方式&#xff0c;就肯定不会有乱码问题&#xff0c;但这是不可能的。keil 设置编码格…

SpringMVC入门篇

目录 1.SpringMVC工作流程 2.SpringMVC核心组件 2.1 DispatcherServlet 2.2 HandlerMapping 2.3 Handler 2.4 HandlerAdapter 2.5 ViewResolver 2.6 View 3.SpringMVC的入门 3.1 添加相关依赖 3.2 创建Spring-mvc.xml 3.3 配置web.xml 3.4 效果演示 4.静态资源处…

计算机视觉CV:在自动驾驶方面的应用与C++代码实现

1.计算机视觉&#xff08;CV&#xff09;在自动驾驶领域中的应用 目标检测&#xff1a;利用计算机视觉技术&#xff0c;对道路上的各种障碍物进行识别和检测&#xff0c;例如行人、车辆、信号灯等等。 路径规划&#xff1a;利用计算机视觉技术&#xff0c;实时分析道路上的交通…

二叉搜索树

如何搜索构建一颗二叉搜索树插入删除 如何搜索 在二叉搜索树里搜索值&#xff1b;搜索非常类似于二分查找 //查找key是否存在public TreeNode search(int key) {TreeNode cur root;while(cur ! null) {if(cur.key key) {return cur;}else if(cur.key > key){cur cur.lef…