【JUC进阶】05. 偏向锁

news2024/12/23 22:06:44

目录

1、前言

2、偏向锁

2.1、基本原理

2.2、使用场景

3、获取偏向锁

4、何时撤销

4.1、到达安全点

4.2、其他线程尝试竞争偏向锁

4.3、重新计算hashcode

5、小结


1、前言

偏向锁是Java并发编程中一种重要的锁机制,它针对特定的线程进行优化,从而提高了并发性能。这种锁机制在多线程场景下非常常见,特别适用于一些读写分离的应用场景。

2、偏向锁

2.1、基本原理

偏向锁是一种对线程友好的锁机制,它的核心思想是通过对线程的识别和追踪,以及对锁的竞争状况进行动态分析,来决定是否启用偏向锁。

当一个线程访问一个被标记为同步块的对象时,如果该对象没有被其他线程占用,则该线程将直接获得该对象的锁;如果该对象已经被其他线程占用,则该线程将进入自旋状态,不断检查该对象是否被其他线程占用,直到获取到该对象的锁。

简单的说就是:如果一个线程获得了锁,那么锁就进入偏向模式。当这个线程再次请求锁的时候,无须再做任何同步操作。这样节省了大量关于锁申请的操作,而提升性能。这是JDK对于锁优化做的一种努力。

因此,对于几乎没有锁竞争的场合,偏向锁有较好的优化效果,因为连续多次极有可能是同一个线程请求的锁。而对于锁竞争比较激烈的场合,就不太理想了,因为在这种场合下,最有可能获得锁的都是来自不同的线程。

2.2、使用场景

偏向锁主要用于解决读写锁带来的性能问题。在读写锁中,每次读写操作都需要进行加锁和解锁操作,而这些操作会消耗大量的CPU时间。

偏向锁则通过一种乐观锁的机制,将线程分为读线程和写线程两种类型,对于读线程而言,只要没有写线程在修改共享数据,读线程就可以直接访问共享数据,而无需进行加锁和解锁操作。当有写线程在修改共享数据时,其他线程需要自旋等待,这在一定程度上提高了程序的并发性能。

3、获取偏向锁

在JDK6开始,HotSpot虚拟机就开启了-XX:UseBiasedLocking参数,默认启用了偏向锁。当锁对象第一次被线获取的时候,虚拟机将会把对象头中的标志位设置为“01”、把偏向模式设置为“1”,表示进入偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的 Mark Word之中。如果 CAS 操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作(例如加锁、解锁及对 Mark Word 的更新操作等)。

一旦出现另外一个线程去尝试获取这个锁的情况,偏向模式就马上宣告结束。根据锁对象目前是否处于被锁定的状态决定是否撤销偏向(偏向模式设置为“0”),撤销后标志位恢复到未锁定(标志位为“01”)或轻量级锁定(标志位为“00”)的状态。

梳理一下流程图:

我们可以看到,当对象进入偏向状态的时候,Mark Word的大部分空间都用于存储持有锁的线程ID了,原有的这部分空间是存储的对象哈希码。

实际上,偏向锁的对象头中是没有空间存储hash值的。

jvm中对偏向锁的实现如下:

// 偏向锁加锁操作  
bool BiasedLocking::biased_locking_acquire(oop obj, JavaThread* thread) {  
    int thread_id = get_thread_id();  
    int* lock_word = get_header_address(obj);  
  
    // 检查是否已经存在锁拥有者  
    if (*lock_word & 0x1) {  
        return false; // 已经存在锁拥有者,直接返回false  
    }  
  
    // 检查是否需要升级为重量锁  
    if ((*(lock_word) & 0x2) == 0) {  
        if (Atomic::cmpxchg(EXPECTED_BIAS, lock_word, lock_word - 1) != (int)thread_id - 1) {  
            return false; // 升级失败,锁已经被其他线程获取,直接返回false  
        } else {  
            // 升级成功,将线程ID写入锁拥有者字段中,并标记为重量锁  
            *lock_word = thread_id | 0x2;  
            thread->set_next(NULL); // 断开与队列中其他线程的连接  
            return true; // 升级成功,返回true  
        }  
    } else {  
        return true; // 已经是重量锁,直接返回true  
    }  
}  
  
// 偏向锁解锁操作  
void BiasedLocking::biased_locking_release(oop obj, JavaThread* thread) {  
    int thread_id = get_thread_id();  
    int* lock_word = get_header_address(obj);  
    if (*lock_word != 0) {  
        if ((*lock_word) & 0x2) {  
            // 如果是重量锁,直接将线程ID写入锁拥有者字段中,并标记为无锁状态  
            Atomic::cmpxchg((int)thread_id, lock_word, lock_word - 1);  
        } else {  
            // 如果是偏向锁,则将线程ID写入锁拥有者字段中,并标记为无锁状态,同时唤醒等待队列中的线程  
            Atomic::cmpxchg((int)thread_id, lock_word, lock_word - 1);  
            BiasedLocking::Biased_locking_unpark(thread);  
        }  
    } else {  
        // 如果已经是无锁状态,则直接返回,不做任何操作  
    }  
}

4、何时撤销

4.1、到达安全点

偏向锁的撤销需要等待全局安全点(safe point),此时会暂停所有线程,然后检查持有偏向锁的线程是否还活着,如果线程不处于活动状态,则将对象头设置成无锁状态;如果线程仍然活着,则需要遍历持有偏向锁的栈,检查是否存在其他对象头和该对象头不一致,如果存在,则需要重新偏向该线程。最后唤醒暂停的线程。

4.2、其他线程尝试竞争偏向锁

前面也提到了。当出现另一个线程尝试获取偏向锁的情况下,持有偏向锁的线程才会释放锁,线程不会主动释放偏向锁。

4.3、重新计算hashcode

前面对象头里面我们可以看到,当一个对象持有偏向锁时,对象头是不存储hashcode的。那么原先存储的对象hashcode怎么办呢?实际上,当一个对象计算过一致性hash后,就再也无法进入偏向锁状态了。而当一个对象当前正处于偏向锁状态,又收到需要计算其一致性哈希码请求时,它的偏向状态会被立即撤销,并且锁会膨胀为重量级锁。在重量级锁的实现中对象头指向了重量级锁的位置,代表重量级锁的 ObjectMonitor类里有字段可以记录非加锁状态(标志位为“01”)下的Mark Word,其中自然可以存储原来的哈希码。

5、小结

偏向锁可以提高带有同步但无竞争的程序性能,但它同样是一个带有效益权衡(TradeOff)性质的优化,也就是说它并非总是对程序运行有利。如果程序中大多数的锁都总是被多个不同的线程访问,那偏向模式就是多余的。在具体问题具体分析的前提下,有时候使用参数-XX:-UseBiasedLocking 来禁止偏向锁优化反而可以提升性能。

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

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

相关文章

项目集活动—项目集收尾阶段活动

项目集收尾阶段活动从项目集组件完成了所有输出的交付,且项目集开始交付预期效益。某些情况下,项目集治理可能决定在所有组件完成之前就提前执行项目集收尾。无论哪种情况,此阶段项目集活动的目标都是释放项目集资源,支持将剩余项…

区分BOM和DOM,区分window、document、html、body

https://blog.csdn.net/xswl134679/article/details/128795161 JavaScript三大组成部分 1. ECMAScript ECMAScript是JavaScript的语法标准,由ECMA(欧洲计算机厂家协会)制定的。 2. BOM BOM即浏览器对象模型(brower object mode…

Contrastive Learning in Image (CVPR 2023)

文章目录 1. Open Vocabulary Semantic Segmentation with Patch Aligned Contrastive Learning (图文匹配)1.目标2.任务类型3.解决思路4. 总结 2. MaskCLIP: Masked Self-Distillation Advances Contrastive Language-Image Pretraining (图…

数学模型在水环境评价、防洪评价、排污口论证、水质、水量、水生态、水动力等方面的应用

目录 专题一、一维水动力模型模拟一河道水流的应用 专题二、一维复杂河网模型构建及建筑物设置 专题三、一维水质模型在环境影响评价中的应用 专题四、平面二维水动力模型的构建河验证 专题五、平面二维水动力模型在防洪影响评价中的应用 专题六、平面二维水动力水质模型…

抖音kol投放模型怎么打造,营销策略规划

这是一个内容为王的时代,想要在小红书这种内容平台做好内容营销,一定要了解抖音kol投放模型怎么打造,营销策略规划。 一、如何进行kol投放 品牌想要完成一次高效而准确的完成kol投放模型,需要完整的品牌投放策略。针对于小红书平台…

如何驯化机器狗读懂人类手势,手把手教你!

作为全国普通高校大学生竞赛榜单内竞赛,“中国软件杯”大学生软件设计大赛-智能四足机器狗电力巡检系统开发赛项,目前已吸引了全国2041支队伍参加。经过激烈的目标检测与分割算法打榜赛,最终,有153支团队成功晋级区域赛。在即将于…

知乎财报预测:知乎2023年Q2收入将继续下滑,净亏损将扩大一倍

来源:猛兽财经 作者:猛兽财经 华尔街分析师对知乎2023年第二季度财报的预测 在5月24日发布第一季度业绩时,知乎(ZH)并未对2023年第二季度或2023财年全年提供任何具体的指引。但目前卖方分析师的一致财务预测表明&…

F-35飞控系统详解

基于非线性动态逆(NDI)的控制律 1. F-35飞控控制律 F-35采用了由三台冗余机载管理计算机(VMC,Vehicle Management Computers)中运行的非线性动态逆控制架构来提供电传飞行控制。F-35的控制律不仅能增强飞机动力学特性实现增稳,还…

java学习记录之JDBC2

1 JDBC回顾  Statement 语句执行者 Connection conn null; Statement st null; ResultSet rs null; try{ //1 通过工具类获得连接 conn JdbcUtils.getConnection(); //2 获得语句执行者 st conn.createStatement() --> 参数 结果集类型、并发参数 (滚动结…

如何在 Spring Boot 中使用定时任务

如何在 Spring Boot 中使用定时任务 引言 在实际的项目中,我们经常需要编写定时任务来执行一些周期性的任务,比如定时备份数据库、定时发送邮件等。在 Spring Boot 中,我们可以使用 Spring 的 Task Execution 和 Scheduling 来实现定时任务…

用BERT做命名实体识别任务

命名实体识别NER任务是NLP的一个常见任务, 它是Named Entity Recognization的简称。 简单地说,就是识别一个句子中的各种 名称实体。 诸如:人名,地名,机构 等。 例如对于下面这句话: 小明对小红说:"你…

佩戴舒适度的蓝牙耳机品牌有哪些?佩戴舒适性蓝牙耳机排行榜推荐

​对于年轻人来说,耳机使用场景丰富,时尚追求度高,喜好的音乐类型也是多种多样,需求侧重也不尽相同。下面我来推荐几款相当不错的蓝牙耳机给大家,总会有喜欢那款! 一、南卡OE PRO开放式耳机 南卡OE PRO是国…

带你阅读 Flutter Demo(flutter 保姆级入门教程)

dart、flutter Flutter Demo 解析 - 文章信息 - Author: Jack Lee (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChineAddress of this article:https://blog.csdn.net/qq_28550263/article/details/xxxxxx 【介绍】:本…

RFID技术的革新与应用:连接智能物联网的关键

在日益数字化的时代,物联网(IoT)技术正迅速发展,并为我们的生活带来了无数的便利。而射频识别(RFID)技术作为物联网的关键支撑之一,正在推动着智能化、自动化的进程。本文将深入探讨RFID技术的基…

INTERSPEECH 2023论文|基于自监督学习表示的具有持久性口音记忆的口音识别

论文题目: Self-supervised Learning Representation based Accent Recognition with Persistent Accent Memory 作者列表: 李睿,谢志伟,徐海华,彭亦周,刘和鑫,黄浩,Chng Eng Sio…

神州设备IPV6路由综合运用

实训拓扑图 一、基本配置: SW-1: SW-1>ena SW-1#conf SW-1(config)#vlan 10;100 SW-1(config)#int l1 SW-1(config-if-loopback1)#ip add 1.1.1.1 255.255.255.255 SW-1(config-if-loopback1)#ipv6 add 2001:1::1/128 SW-1(config-if-loopback1)#exit

前端系列18集-权限,nginx成功,屏幕分辨率,vue3

vue3.0 使用原生websocket通信 // Websoket连接成功事件const websocketonopen (res: any) > {console.log("WebSocket连接成功", res);};// Websoket接收消息事件const websocketonmessage (res: any) > {console.log("数据", res);};// Websoket…

【从零开始学习C++ | 第二十二篇】C++新增特性(下)

目录 前言: 类型推导: constexpr关键字: 初始化列表: 基于范围的for循环: 智能指针之unique ptr Lambda表达式: 总结: 前言: 本文我们将继续介绍 C 11 新增十大特性的剩余…

解决前端容器不能充满屏幕

解决前端容器不能充满屏幕 px、rpx、em、rem、vw、vh各种像素单位的区别 css3新单位vw、vh、vmin、vmax的使用详解 学习element-UI写管理系统的页面,发现当菜单栏都收缩起来,结果是这样的 红色框是容器里每个板块的布局,但是容器下面却有空白…

如何处理兼容性测试中的变更管理?

如何处理兼容性测试中的变更管理? 在进行软件测试的过程中,兼容性测试是非常重要的一环。然而,在进行兼容性测试时,由于涉及到不同平台、不同设备的适配问题,可能会出现许多变更管理的情况。这时候,如果没…