双非本科准备秋招(19.1)—— Synchronized优化

轻量级锁

流程

        一个对象虽然有多线程加锁,但是加锁时间是错开的,那么可以用轻量级锁优化。

        语法还是synchronized,只是对使用者是透明的。

static final Object obj = new Object();
public static void method1() {synchronized( obj ) {// 同步块 Amethod2();}
}
public static void method2() {synchronized( obj ) {// 同步块 B}
}

        首先,会先创建锁记录(Lock Record)对象,每个线程的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的 Mark Word

        

        然后,让锁记录中 Object reference 指向锁对象,并尝试用 cas 替换 Object 的 Mark Word,将 Mark Word 的值存 入锁记录

替换分为成功和失败:

        替换成功

        锁记录中存储了对象的MarkWord,00代表轻量级锁,01代表无锁。

        

        替换失败

  • 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程
  • 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

        当解锁时,如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一

        如果锁记录的值不为 null,这时使用 cas 将 Mark Word 的值恢复给对象头。

替换也分为成功失败。

  • 成功,则解锁成功
  • 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

锁膨胀

        如果尝试加轻量级锁无法成功,一种情况是有竞争,这时需要进行锁膨胀,将轻量级锁变为重量级锁

        假设锁对象是Object,那就会为 Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址

        然后自己这个线程进入 Monitor 的 EntryList ,被阻塞。

        当获得锁的那个线程解锁时,将 Mark Word 的值恢复给对象头,会失败(因为锁对象指向了Monitor,而不是交换的MarkWord值)。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner 为 null,唤醒 EntryList 中的线程。

自旋优化

        重量级锁竞争的时候,还可以使用自旋来进行优化,自旋成功可以避免阻塞。

        自旋会占用 CPU 时间,单核 CPU 自旋就是浪费(单线程你旋个鸟,老老实实阻塞就行),多核 CPU 自旋才能发挥优势。

        在 Java 6 之后自旋锁是自适应的,比较智能,会根据实际情况改变自旋次数。

        Java 7 之后不能控制是否开启自旋功能,也就是底层实现,与我们程序员无关了。

偏向锁

        轻量级锁在没有竞争时,每次重入仍然需要执行 CAS 操作,偏向锁就是为了解决重入问题的。

        Java 6 中引入了偏向锁:只有第一次使用 CAS 将线程 ID 设置到对象的 Mark Word ,之后发现 这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。

static final Object obj = new Object();
public static void m1() {synchronized( obj ) {// 临界区m2();}
}
public static void m2() {synchronized( obj ) {// 临界区m3();}
}
public static void m3() {synchronized( obj ) {// 临界区}
}

轻量级锁流程如下:

如果用偏向锁优化:

        一个对象创建时: 如果开启了偏向锁(默认开启),那么对象创建后,markword 最后 3 位为 101(001代表normal),这时它的 thread、epoch、age 都为 0

        偏向锁是默认是延迟的,可以加 VM 参数 XX:BiasedLockingStartupDelay=0 来禁用延迟

        如果没有开启偏向锁,那么对象创建后,markword 最后 3 位为 001,这时它的 hashcode、 age 都为 0,第一次用到 hashcode 时才会赋值

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

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

相关文章

代码随想录算法训练营第42天 | 01背包理论基础 416.分割等和子集

01背包理论基础 问题定义:有n件物品和一个能装重量为w的背包,第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包获得的总价值最大。dp数组含义:dp[i][j] 表示从下标为 [0…

(篇九)MySQL常用内置函数

目录 ⌛数学函数 ⌛字符串函数 ⌛聚合函数 ⌛日期函数 📐获取当前时间 📐获取时间的某些内容 📐​编辑 📐格式化函数 📏format类型: ⌛系统信息函数 ⌛类型转换函数 数学函数 字符串函数 聚合函…

3060ti显卡+cuda12.1+win10编译安装生成fastdeploy的c++与python库

在cuda12中,调用官方发布的fastdeploy会出现报错,故此自行编译fastdeploy库。 官网编译教程:https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md 可选编译选项 编译选项 无论是在何平台编译,编译时仅根据需求修改如下选项,勿…

【大模型上下文长度扩展】MedGPT:解决遗忘 + 永久记忆 + 无限上下文

MedGPT:解决遗忘 永久记忆 无限上下文 问题:如何提升语言模型在长对话中的记忆和处理能力?子问题1:有限上下文窗口的限制子问题2:复杂文档处理的挑战子问题3:长期记忆的维护子问题4:即时信息检…

cpp11新特性之智能指针(下):深入理解现代cpp中的智能指针shared_ptr、unique_ptr 以及 weak_ptr

目录 写在前面 unique_ptr shared_ptr weak_ptr 智能指针的使用陷阱 致谢 写在前面 上一篇文章同大家深入探讨了auto_ptr。今天给大家带来的是对于 shared_ptr、unique_ptr 以及 weak_ptr 的深入理解,通过测试案例和源码剖析对这三种重要的智能指针的使用方法&…

Docker的镜像和容器的区别

1 Docker镜像 假设Linux内核是第0层,那么无论怎么运行Docker,它都是运行于内核层之上的。这个Docker镜像,是一个只读的镜像,位于第1层,它不能被修改或不能保存状态。 一个Docker镜像可以构建于另一个Docker镜像之上&…

COMSOL接触(高度非线性)仿真常见报错及解决方法总结

前言 由于COMSOL采用隐式求解器,相较于使用显式求解器的Dyna、Abaqus等软件。要在COMSOL中实现结构接触这一高度非线性问题难度较大,报错时有发生。究其原因,是当物体之间相互接触时,物体受到的应力、运动路径会发生突变&#xff…

Qt Windows和Android使用MuPDF预览PDF文件

文章目录 1. Windows MuPDF编译2. Android MuPDF编译3. 引用 MuPDF 库4. 解析本地PDF文件 1. Windows MuPDF编译 使用如下命令将MuPDF的源码克隆到本地 git clone --recursive git://git.ghostscript.com/mupdf.git直接用VS,打开 mupdf/platform/win32/mupdf.sln …

FPGA_vga显示

一 VGA 1.1 VGA VGA是视频图像阵列,是一种使用模拟信号进行视频传输的标准协议。 1.2 VGA接引脚定义 VGA分公母两种,RGB显示标准。 1.3 VGA显示器 VGA显示器采用图像扫描的方式进行图像显示,将构成图像的像素点,在行同步信号…

如何在 emacs 上开始使用 Tree-Sitter(windows)

文章目录 如何在emacs上开始使用Tree-Sitter(windows) 如何在emacs上开始使用Tree-Sitter(windows) 参考:“How to Get Started with Tree-Sitter”。 首先要有一个可运行的emacs,并且它支持Tree-Sitter&…

【C++】中的 inline 用法

1、引入 inline 关键字的原因 在 c/c 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。 栈空间就是指放置程序的局部数据(也就是函数内数据&a…

Python环境下基于辛几何模态分解的信号分解方法

基于辛几何的分析方法是一种保护相空间几何结构的新型分析方法,主要用于求解动力学和控制系统中矩阵或Hamilton矩阵的特征值问题,用来解决在动力学和控制系统理论的2n2n矩阵或哈密顿矩阵的特征值问题,已应用到结构损伤信号、奇异微分方程等系…

Visio 2019下载安装教程,保姆级教程,附安装包

前言 Visio是负责绘制流程图和示意图的软件,便于IT和商务人员就复杂信息、系统和流程进行可视化处理、分析和交流,可以促进对系统和流程的了解,深入了解复杂信息并利用这些知识做出更好的业务决策。帮助您创建具有专业外观的图表&#xff0c…

mac电脑安装cocoapods出错,以及安装最新版本ruby方法

macbook安装cocoapods时碰到一个报错:大概率是ruby的版本太低导致的 sudo gem install cocoapods ERROR: Error installing cocoapods: ERROR: Failed to build gem native extension. ... Could not create Makefile due to some reason, probably lack of neces…

redisson源码解析

由于synchronized跟ReetrantLock是JVM级别的锁,在分布式情况下失效,这时候我们通常会选择redisson基于redis封装好的分布式锁。下面我们一起来分析以下redisson的源码。 使用方式 流程 getLock源码 给命令执行器赋值给看门狗时间赋值,默认30…

年假作业day2

1.打印字母图形 #include<stdio.h> #include<string.h> int main(int argc, const char *argv[]) { int i,j; char k; for(i1;i<7;i) { for(j1;j<i;j) { printf("%c",_); } for(j0,…

GetBilibiliVideo:一个下载B站视频的开源神器,让你轻松管理你的二次元世界。

正文&#xff1a; 引言 在广大ACG爱好者和内容创作者之间&#xff0c;哔哩哔哩&#xff08;Bilibili&#xff09;已经成为了不可或缺的视频分享与学习平台。为了满足用户对B站视频离线观看及备份的需求&#xff0c;我精心开发了一个名为 GetBilibiliVideo 的开源工具&#xf…

如何将mongodb+django部署到云服务器上(备份)

在有了一台云服务器之后&#xff0c;我们就可以把写在本机上的程序&#xff0c;搬到服务器上了。采用WinSCP在本机和服务器之间交换文件&#xff1b;FinalShell来操作服务器。 1、mongodb-本机到服务器 主要是三个步骤&#xff1a;dump本地数据库-上传-导入&#xff0c;详情请…

tkinter绘制组件(41)——菜单按钮

tkinter绘制组件&#xff08;41&#xff09;——菜单按钮 引言布局函数结构按钮部分菜单显示完整代码函数 效果测试代码最终效果 github项目pip下载结语 引言 TinUI5的新控件&#xff0c;菜单按钮&#xff0c;menubutton。 这是一个与TinUI菜单&#xff08;menubar&#xff0…

ctfshow——命令执行

文章目录 web 29——通配符*绕过web30——调用其他命令执行函数web 31——参数逃逸web 32-web 36——配合文件包含伪协议web 37-web 39——文件包含web 40—— web 29——通配符*绕过 i不区分大小写&#xff0c;直接?csystem(tac fl*.php); web30——调用其他命令执行函数 调用…