synchronized轻量级锁原理和实战(四)

引入轻量级锁的目的

多线程竞争不激烈的情况下,通过CAS机制竞争减少重量级锁产生的性能消耗.重量级锁使用了操作系统底层的互斥锁,会导致线程在用户态和核心态之间切换.带来性能上的损耗.

轻量级锁的核心原理

轻量级锁存在的目的本身就是为了减少线程从内核态和用户态的切换,从而提高性能.通过经验可以发现好多加锁操作并不会持续很长时间.比如整数的自加操作,在很短的时间阻塞和唤醒线程显然不是很合理.轻量级锁是一种自旋锁,因为JVM本身就是一个应用,希望从应用层面通过自旋解决线程同步问题.

轻量级锁执行过程

抢锁线程进入临界区之前.如果内置锁(临界区的同步对象)没有锁定.JVM首先在抢锁线程的栈帧中建立一个锁记录(Lock Record),用于存储对象目前的Mark Word拷贝.

抢锁线程先处理好栈帧中的轻量级锁记录,然后就是最核心的CAS自旋.抢锁线程通过自旋操作,尝试将内置锁对象头的Mark Word的ptr_lock_record(锁记录指针)更新为抢锁线程中锁记录的地址.如果更新成功了,这个线程就拥有了这个对象锁.然后JVM会把Mark Word的锁记录标记位改为00(轻量级锁标志).

Mard Word的值被更新成功后,包含锁对象信息(如哈希表等)旧值会返回来,抢锁线程会找到一个地方将旧的Mark Word值存起来,所以线程在通过CAS自旋操作更新完Mark Word之后还会有两个善后操作.

1:将含有锁对象信息(如哈希表等)旧的Mark Word值保存在抢锁线程Lock Record的Displaced Mark Word(可以理解为放错的Mark Word)字段中,这一步起到备份作用,以便锁释放以后将旧的值恢复到锁对象头部.

2:抢锁线程将栈帧中的锁记录owner指针指向锁对象.

锁记录是线程私有的,每个线程都有自己的一份锁记录,在创建完锁记录后,会将内置锁对象的Mark Word拷贝到锁记录的Displaced Mark Word字段.这是因为什么?因为内置锁对象的Mark Word的结构会有所变化,Mark Word将会出现一个指向锁记录的指针,而不再存着无锁状态下的锁对象的哈希码等信息,所以必须将这些信息先暂存起来,供后面使用.

轻量级锁演示

public class LightweightLock {static final int MAX_TURN = 1000;public static void main(String[] args) throws InterruptedException {System.out.println(VM.current().details());//JVM偏向延迟锁.Thread.sleep(5000);ObjectLock objectLock = new ObjectLock();System.out.println("抢占锁前lock的状态:");objectLock.printObjectStruct();LockSupport.parkNanos(5000);CountDownLatch latch = new CountDownLatch(2);Runnable runnable = () -> {for (int i = 0; i < MAX_TURN; i++) {synchronized (objectLock) {objectLock.increase();if (i == 1) {System.out.println("第一个线程占有锁,lock的状态为: ");objectLock.printObjectStruct();}}}latch.countDown();//线程虽然释放锁,但是存在死循环.for (int j = 0; ; j++) {//每一次循环等待一毫秒.LockSupport.parkNanos(1000);}};new Thread(runnable).start();LockSupport.parkNanos(1000);Runnable LightweightRunnable = () -> {for (int i = 0; i < MAX_TURN; i++) {synchronized (objectLock){if (i == MAX_TURN / 2) {System.out.println("第二个线程占有锁,lock的状态为: ");objectLock.printObjectStruct();}LockSupport.parkNanos(1000);}}//循环完毕.latch.countDown();};new Thread(LightweightRunnable).start();latch.await();LockSupport.parkNanos(2000);System.out.println("释放锁后的状态: ");objectLock.printObjectStruct();}
}

程序启动五秒以后,ObjectLocal状态为偏向锁.

 

关于偏向锁的执行结果和上一篇文章相同,就不啰嗦啦.

当第二个抢锁线程抢锁成功后,ObjectLock状态变成了轻量级锁.

 

可以看到lock标记位改为了00(轻量级锁标志),其中ptr_to_lock_record(锁记录指针)更新为抢锁线程栈帧中Lock Record的地址.

轻量级锁被释放后.ObjectLock状态变成无锁状态,lock标记位01(无锁标志).

轻量级锁的分类

轻量级锁主要有两种.普通自旋锁和自适应自旋锁.

1:普通自旋锁

普通自旋锁就是当线程来竞争锁时,抢锁线程会原地等待,而不是被阻塞.直到那个占有锁的线程释放锁.这个线程才可以获取锁.默认情况下,自旋的次数为10次.可以通过-XX:PreBlockSpin进行更改.

2:自适应自旋锁

自适应自旋锁,就是等待线程空循环次数并非是固定的.而是会动态的根据情况来改变自旋次数.自旋次数由上次获取锁的状态来决定.

原理

1:如果抢锁线程在同一个对象上之前成功的获取过锁,那么JVM会认为这次自旋也很有可能获取到锁,所以自旋的次数会多一些.

2:如果对于某个锁,抢锁线程很少获取到锁,那么JVM就会减少这个线程的自旋次数,甚至省去自旋过程,避免浪费处理器资源.

自适应自旋锁主要解决的是锁竞争时间不确定的问题.根据上一次自旋次数和结果来调整下一次自选的次数.

轻量级锁的膨胀

轻量级锁是为了减少多线程抢锁情况下进入操作系统底层的互斥锁的概率,并不是要去替代操作系统的互斥锁.所以在竞争激烈的情况下,轻量级锁会膨胀为重量级锁.

时间一分一秒的流逝,我们又留下了什么.是一身反骨,还是甘愿被磨平棱角.

如果大家喜欢我的分享的话,可以关注下我的微信公众号

心有九月星辰

 

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

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

相关文章

笔试必备—Java输入输出流

Java 流 流可以理解为一个数据&#xff0c;输入流表示从一个源读取数据&#xff0c;输出流表示向一个目标写数据 Java 为 I/O 提供了强大的而灵活的支持&#xff0c;使其更广泛地应用到文件传输和网络编程中 Scanner类 提供了一系列的方法&#xff0c;更加直观、易用性高&…

【数学建模】趣味数模问题——四人追逐问题

问题描述&#xff1a; 如图所示&#xff0c;在正方形ABCD的四个顶点各有一个人。在初始时刻 t0 时&#xff0c;四人同时出发&#xff0c;以匀速 v 沿顺时针方向朝下一个人移动。如果他们始终对准下一个人为目标行进&#xff0c;最终结果会如何&#xff1f;需要作出各自的运动轨…

微信小程序 ==== 半屏打开小程序

目录 打开半屏小程序 调用流程 打开半屏小程序 半屏小程序环境判断 返回原小程序 使用限制 wx.openEmbeddedMiniProgram 功能描述 参数 wx.navigateBackMiniProgram 功能描述 示例代码 Object wx.getEnterOptionsSync() 功能描述 返回值 返回有效 referrerInfo…

计算机毕业设计 医院问诊系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Spring Boot集成Devtools实现热更新?

1.什么Devtools&#xff1f; DevTools是开发者工具集&#xff0c;主要用于简化开发过程中的热部署问题。 热部署是指在开发过程中&#xff0c;当代码发生变化时&#xff0c;无需手动重启应用&#xff0c;系统能够自动检测并重新加载修改后的代码&#xff0c;大大提高了开发效率…

UE基础 —— 关卡

目录 Working with Levels Managing Multiple Levels World Settings 更改默认关卡 关卡&#xff08;Level&#xff09;是游戏的"世界"的全部或部分&#xff1b;关卡包含玩家可以看到并与之交互的所有内容&#xff0c;如环境、可用对象、其他角色&#xff0c;等等…

理性看待、正确理解 AI 中的 Scaling “laws”

编者按&#xff1a;LLMs 规模和性能的不断提升&#xff0c;让人们不禁产生疑问&#xff1a;这种趋势是否能一直持续下去&#xff1f;我们是否能通过不断扩大模型规模最终实现通用人工智能&#xff08;AGI&#xff09;&#xff1f;回答这些问题对于理解 AI 的未来发展轨迹至关重…

郊游、旅游管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

【算法/学习】双指针

✨ 少年要迎着朝阳&#xff0c;活得肆无忌惮 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;算法学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &a…

python语言day6 os random datetime .ini文件

os&#xff1a; 获取运行当前py文件的绝对路径&#xff1a; abspath中添加路径&#xff0c;会直接和绝对路径拼接。 folder_path os.path.abspath("") print(folder_path) 路径拼接&#xff1a; mac系统路径&#xff1a;file/TranslucentTB win系统路径&#xff1a;…

python爬虫滑块验证及各种加密函数(基于ddddocr进行的一层封装)

git链接: https://github.com/JOUUUSKA/spider_toolsbox 这里写目录标题 一.识别验证码1、识别英文&#xff0b;数字验证码2、识别滑块验证码3、识别点选验证码 二、下载系列1、下载视频2、下载图片3、下载文本 三、常用加密类型1、AES系列2、DES系列3、RSA系列4、SHA系列5、B…

【c++】深入理解别名机制--引用

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C 目录 前言 一、引用的概念和定义 二、引用的特性 三、引用的实用性 1.引用传参 2.引用做返回值 2.1 引用做返回值的作用 2.2 引用坍缩问题、悬挂引用问…

算法的学习笔记—合并两个排序的链表(牛客JZ25)

&#x1f600;前言 在算法面试中&#xff0c;链表问题是经常遇到的考点之一&#xff0c;其中合并两个排序链表是一个非常经典的问题。本文将详细介绍如何通过递归和迭代两种方式实现两个有序链表的合并。 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 &#x1f600;合并…

Arduino开源四足蜘蛛机器人制作教程

视频教程&#xff1a;手把手叫你做四足蜘蛛机器人——1零件介绍_哔哩哔哩_bilibili 一、项目介绍 1.1 项目介绍 Arduino主控&#xff0c;图形化编程&#xff0c;趣味学习 Arduino nano开发板舵机扩展底板 4.8V可充电电池&#xff0c;支持Arduino C语言编程和米思齐图形化编程…

打卡学习Python爬虫第三天|爬取豆瓣电影Top250排行榜(附源码)

一、打开网页找到url 二、查看数据是否存在于网页源代码中 三、编写代码获取网页源代码 1、获取电影名称 注意正则表达式的使用&#xff0c;先观察网页源代码&#xff0c;我们发现每一部电影的数据存放在一个<li></li>中&#xff0c;如上图。并且我们要获取的电影…

el-image 图片预览时 与 el-table (或avue-crud) 样式冲突 的解决

问题: 解决 <style scoped> ::v-deep(.el-table__cell) {position: static !important; } </style> 后效果

二十二、状态模式

文章目录 1 基本介绍2 案例2.1 Season 接口2.2 Spring 类2.3 Summer 类2.4 Autumn 类2.5 Winter 类2.6 Person 类2.7 Client 类2.8 Client 类的运行结果2.9 总结 3 各角色之间的关系3.1 角色3.1.1 State ( 状态 )3.1.2 ConcreteState ( 具体的状态 )3.1.3 Context ( 上下文 )3.…

二叉树练习习题集一(Java)

1. 思路&#xff1a; 就是让左孩子和右孩子进行交换&#xff0c;这里需要一个中间变量用来记录&#xff0c;然后完成交换。如果进行优化则添加当左孩子和右孩子都为null时直接返回。 class Solution {public TreeNode invertTree(TreeNode root) {TreeNode tmpnull;//用来进行…

网络原理知识总结

一、网络模型 1.1 osi七层参考模型 物理层&#xff1a;连接通信链路、传输比特流数据链路层&#xff1a;数据封装成帧&#xff0c;在节点与节点间实现可靠物理地址寻址&#xff0c;进行差错校验、流量控制网络层&#xff1a;逻辑地址寻址&#xff0c;路由选择 IP(IPV4IPV6) I…

window.onload、$(document).ready()、Vue.created() 页面加载完成后执行方法

1、JavaScript 的 window.onload 方法 window.onload 方法是在页面所有元素&#xff08;包括图片、样式、链接等&#xff09;加载完成后触发的&#xff0c;在这个事件之前&#xff0c;页面上的所有资源都必须加载完成。因此&#xff0c;如果页面中包含大量的图片或其他资源&am…