synchronized底层原理

news2024/11/15 15:29:30

synchronized是JVM内置锁,基于monitor机制实现,依赖底层操作系统的互斥源语Mutex(互斥量),它是一个重量级锁,性能较低。
当然,JVM内置锁在1.5之后版本做了重大优化,如锁粗化,锁消除、轻量级锁、偏向锁、自适应锁、等技术来减少操作的开销,内置锁的并发性能已经基本与lock持平。

java虚拟机通过一个同步结构支持方法和方法中的指令序列的同步:monitor。

同步方法是通过方法access_flags中设置ACC_SYNCHRONIZED标志来实现;
同步代码块是通过 ** monitorenter ** 和 ** montorexit ** 来实现。
两个指令的执行是JVM通过调用操作系统的互斥原语mutex来实现的,被阻塞的线程会被挂起、等待重新调度,
会导致 **用户态和内核态** 两个态之间来回切换,对性能有较大影响。

Monitor (管程/监视器):

Monitor, 直译为监视器,而操作系统领域一般翻译为 管程。 管程是指管理共享变量以及对共享变量操作的过程,让它们支持并发。
在java1.5之前,java语言提供的唯一并发语言就是管程,java1.5之后提供的SDK并发包也是以管程为基础的。除了java之外,C/C++
C#等高级语言也都是支持管程的。synchronized关键字和wait() notify() notifyAll() 这三个方法是java中实现管程技术的组成部分。

MESA模型:

在管程的发展史上,先后出现过三种不同的管程模型,分别是Hasen管程,Hoare模型和MESA模型,现在正在广泛使用的是MESA模型。
在这里插入图片描述
管程中引入了条件变量的概念,而且每个条件变量都对应有一个等待队列。条件变量和等待队列的作用是解决线程之间的同步问题

wait()的正确使用姿势:
对于MESA管程来说,有一个编程范式:

while(条件不满足){
  wait();
}

唤醒的时间和获取到锁继续执行的时间是不一致的,被唤醒的线程再次执行时可能条件又不满足了,所以循环检验条件。
MESA模型的wait() 方法还有一个超时参数,为了避免线程进入等待队列和永久阻塞。

notify()和notifyAll()分别何时使用:
满足一下三个条件,可以使用notify(), 其余情况尽可能使用notifyAll():
1.所有等待线程拥有相同的等待条件
2.所有等待线程被唤醒后,执行相同的操作
3.只需要唤醒一个线程

java语言的内置管程synchronized

Java参考了MESA模型,语言内置的管程(synchronized)对MESA模型进行了精简。MESA模型中,条件变量可以有多个,Java语言内置的管程里面只用一个条件变量。

在这里插入图片描述

Monitor机制在Java中的实现:

java.lang.Object 类定义了wait(), notify(), notifyAll() 方法,这些方法的具体实现,依赖于ObjectMonitor实现,这是JVM 内部基于C++实现的一套机制。
ObjectMonitor 其主要数据结构如何:

ObjectMonitor() {
    _header       = NULL; //对象头  markOop
    _count        = 0;  
    _waiters      = 0,   
    _recursions   = 0;   // 锁的重入次数 
    _object       = NULL;  //存储锁对象
    _owner        = NULL;  // 标识拥有该monitor的线程(当前获取锁的线程) 
    _WaitSet      = NULL;  // 等待线程(调用wait)组成的双向循环链表,_WaitSet是第一个节点
    _WaitSetLock  = 0 ;    
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ; //多线程竞争锁会先存到这个单向链表中 (FILO栈结构)
    FreeNext      = NULL ;
    _EntryList    = NULL ; //存放在进入或重新进入时被阻塞(blocked)的线程 (也是存竞争锁失败的线程)
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;

在这里插入图片描述

在获取锁的时候,是将当前线程插入到cxq的头部,而释放锁时候,默认策略Qmode=0是: 如果EntryList为空,则将cxq中的元素按原有顺序插入到EtryList,并唤醒第一个线程,也就是当EntryList为空时,是后来的线程先获取锁。EntryList不为空,直接从EntryList中唤醒线程。

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

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

相关文章

[红明谷CTF 2021]JavaWeb

0x01 好久没打过ctf了,最近也在学Java 就看下java的题吧 WP 进入环境就提示访问 /login ,访问之后 提示的 /json ,试着访问一下 给了 jessid,继续访问 /json 的话 又会跳转至 /login 应该是要传点username password 果然是了&#…

web制作网页

HTML(人的骨架): 标签 1.超文本标记性语言 2.当前最新版HTML5 3.URL统一资源定位器(网址) 4.网站首页名称index.html,default.htm,main.heml 基本结构: 注意:1.标签都是小写 2.标签成对写 3.代码要层次缩进…

JavaScript内存管理

JavaScript 是一个弱类型的、动态语言,在执行一段 JS 代码时,需要经历编译、执行、内存回收阶段。 一、编译阶段 JS 代码执行时,会首先创建全局执行上下文、以及函数执行上下文,上下文的执行顺序按照栈的方式进行调用&#xff0c…

面试题: JVM内存结构

目录目的资源概览JVM内存溢出分类类型1: OutOfMemoryError类型2: StackOverflowError方法区与永久代、元空间之间的关系目的 学习记录, 面试准备 资源 B站的一个讲高频面试题的一个学习视频 概览 线程私有 ① 程序计数器 ② 虚拟机栈线程共享 ① 堆 ② 方法区 JVM内存溢…

RSA密钥协商过程

目录 TSL握手过程 RSA密钥协商握手过程 TLS第一次握手 TLS第二次握手 客户端验证证书 TLS第三次握手 TLS 第四次握手 RSA 算法的缺陷 TSL握手过程 HTTP 由于是明文传输,所谓的明文,就是说客户端与服务端通信的信息都是肉眼可见的,随…

linux常用指令讲解

文章目录 前言一、指令详解总结前言 Linux是一种自由和开放源代码的类UNIX操作系统,该操作系统的内核由林纳斯托瓦兹在1991年首次发布,之后,在加上用户空间的应用程序之后,就成为了Linux操作系统。严格来讲,Linux只是操…

分布式锁的实现

目录分布式锁分布式锁的引出单体锁存在的问题分布式锁的引出分布式锁的设计思路分布式锁的常见应用场景分布式锁方案分布式锁 分布式锁的引出 单体锁存在的问题 在单体应用中,如果我们对共享数据不进行加锁操作,多线程操作共享数据时会出现数据一致性问…

【Kuangbin简单DP】平整数组

4562. 平整数组 - AcWing题库 题意&#xff1a; 思路&#xff1a; 一开始想的是 设DP状态是&#xff1a;dp[i][0/1]表示阶段到 i &#xff0c;然后前面是递增or递减的最小sum的集合 然后我是怎么转移的呢&#xff0c;现在看来感觉挺好笑的&#xff1a; #include <bits/…

Golang 函数使用的注意事项和细节

来自&#xff1a;尚硅谷-韩老师 尚硅谷 1&#xff09;函数的形参列表可以是多个&#xff0c;返回值列表也可以是多个 2&#xff09;形参列表和返回值列表的数据类型可以是值类型和引用类型 3&#xff09;函数的命名遵循标识符命名规范&#xff0c;首字母不能是数字&#xf…

京东购物成功订单已开具个人发票不能报销怎么申请更换重新开具企业发票用于报销?

原文来源&#xff1a;https://www.caochai.com/article-4109.html 京东购物订单的发票开成个人了可以更换成企业发票吗&#xff1f; 可以&#xff0c;通过京东购物完成的订单默认开个人发票&#xff0c;如果对发票有要求需要开企业发票的可以申请更换重新开企业发票&#xff1…

一文读懂JVM虚拟机:JVM虚拟机的内存管理(万字详解)

JVM虚拟机的内存管理 文章目录JVM虚拟机的内存管理JVM与操作系统Java虚拟机规范和 Java 语言规范的关系java虚拟机的内存管理JVM整体架构一、PC 程序计数器二、虚拟机栈三、本地方法栈四、堆Java 堆概念年轻代和老年代对象分配过程堆GC元空间为什么要废弃永久代&#xff0c;引入…

动手学习深度学习-《矩阵运算》

标量导数 常用求导&#xff1a; yyyaaaxnx^nxnexp(x)exp(x)exp(x)log(x)log(x)log(x)sin(x)sin(x)sin(x)dydx\frac{dy}{dx}dxdy​000nxn−1nx^{n-1}nxn−1exp(x)1x\frac{1}{x}x1​cos(x)cos(x)cos(x) 求导公式&#xff1a; yyyuvuvuvuvuvuvyf(u),ug(x)yf(u),ug(x)yf(u),ug(x)d…

植物大战僵尸:学会使用人造指针

通过向游戏中注入一段特殊的汇编代码&#xff0c;实现自动获取动态地址&#xff0c;省略找基址的麻烦。该方法适用于游戏基址层数过多无法直接获取到基址&#xff0c;游戏根本无法找到基址。 1.打开CE工具并附加游戏进程&#xff0c;首先通过遍历的方式找到阳光的动态地址&…

zookeeper之master选举代码实现

master选举的基本概念 &#xff08;1&#xff09;假设有一个系统A,它向外提供了一个服务&#xff0c;叫做服务B。并且这个服务需要24小时持续不断的向外提供。也就是提供服务的机器不能够有单点故障。于是我们考虑使用集群。 &#xff08;2&#xff09;我们采用的是master-sla…

傻白入门芯片设计,如何做文献笔记(十九)

Article: 文献出处&#xff08;方便再次搜索&#xff09; 作者文献题目文献时间Data: 文献数据&#xff08;总结归纳&#xff0c;方便理解&#xff09; 这篇文章的目的结论背景介绍结果方法&#xff08;可选&#xff09;Comments: 对文献的想法 &#xff08;强迫自己思考&#…

Java人脸识别相册分类按时间分类相册按城市分类相册app源码

简介 后台Java&#xff0c;前台mui开发的android app&#xff1b;主要是按拍摄时间&#xff0c;人脸&#xff0c;城市进行相册照片的分类。 演示视频 https://www.bilibili.com/video/BV1XP4y187rA/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 技…

MySQL调优-Explain详解和索引最佳实践

目录 Explain工具介绍 Explain分析示例 explain 两个变种 explain中的列 1.id列 2.select_type列 3. table列 4.type列 5. possible_keys列 6. key列 7. key_len列 8. ref列 9. rows列 10.Extra列 索引最佳实践 1.全值匹配 2.最左前缀法则 3.不在索引列上做任何操…

2D 平台动作冒险游戏

本文实现比较流畅的跑和跳跃 跑的动画需要从idle经历到walk再到run的过程&#xff0c;这个过程可以用融合树实现 也可以让玩家在按下按键时先固定播放完一个walk的动画&#xff0c;然后再自动切换到run的状态。 只不过在任何状态时&#xff0c;只要玩家松开了按键&#xff0c;…

钧瓷产业数字化,将促使禹州走向更高级的社会形态——钧共体

讲好钧瓷产业的故事 有深度的故事,有温度的内容 有态度的文字,有立场的思考 版权声明:钧瓷内参独家发布,侵权必究 第334期 钧瓷内参 2023年1月1日 这里的上市指沪深的主板,创业板和科创板,区域的挂牌不算。 这个数据是根据禹州钧瓷产业2022…

GPU服务器之Colab配置及使用教程

在进行深度学习过程中&#xff0c;不可避免需要进行炼丹的操作&#xff0c;而博主的电脑本身性能就很拉跨&#xff0c;一旦再运行其他的应用便是寸步难行&#xff0c;最好的办法便是再买一台&#xff0c;哈哈哈&#xff0c;当然也可以使用一些云服务器来进行&#xff0c;博主这…