深入理解synchronized的原理是什么
对象头锁机制原则

Synchronized 的原理是什么
Synchronized 是由JVM实现的一种实现互斥同步的实现方式。如果查看synchronized关键字修饰的字节码,会发现在编译器生成了monitorenter和monitorexit两个字节码指令。

这两个指令的意思就是在虚拟机执行到monitorenter指令的时候,首先尝试获取到对象锁,对象头这部分在对象的最前端,包含两部分或者三部分:Mark Words、Klass Words,如果对象是一个数组,那么还可能包含第三部分:数组的长度。Mark Word需要重点说一下,这里面主要包含对象的哈希值、年龄分代、锁标志位等,大小为32位或64位

如果这个对象没有锁定,或者当前线程已经拥有了这个对象锁,那么就把锁的计数器进行+1操作,当执行monitorexit指令的时候将锁计数器进行-1操作,当计数器为0的时候,锁就被释放了。
如果获取对象失败了,当前线程就要阻塞等待,直到对象锁被另外一个线程释放。
刚刚提到的对象所,这个锁到底是什么?如何确定对象的锁?
锁 的本质是monitorenter和monitorexit 字节码指令的一个Reference类型的参数,也就是是要锁定和解锁的对象。
Synchronized可以修饰不同的对象,所以对应的对象锁可以通过如下的方式确定
- 1、如果Synchronized明确指定了锁定对象,说明加锁对象为该对象。
- 2、如果没有明确指定:
如果Synchronized修饰的方法为非静态方法,表示此方法对应的对象为锁对象;
如果Synchronized修饰的方法为静态方法,则表示这个方法对应的类对象为锁对象。
需要注意的是,当一个对象被锁住的时候,对象里面所有用synchronized修饰的方法都将会被阻塞,而对象里非synchronized修饰方法可以正常被调用,不受到影响。
什么是可重入性,为什么synchronized是可重入锁?
可重入性是锁的基本要求,是为了解决死锁的情况发生。

如图所示,在一个类中同步调用了另一个同步方法,假如synchronized不支持重入,进入method2的时候当前线程获取锁,method2中又执行了method1的时候当前线程又要尝试获取锁,这个时候如果不支持重入,那就要等待释放,所以自己获取锁,自己等释放,就会导致死锁。
对于synchronized来说,重要性是显而易见的。在执行monitorenter指令的时候 ,如果这个对象没有锁定,或者当前线程已经拥有了这对象锁,就把锁的计数器加一,实际上就是通过这种机制来实现锁重入。
JVM对于Java的原生锁做了那些优化
在Java6之前Monitor实现完全依赖底层操作系统的互斥锁来实现,也就是在上面提到的获取/释放锁的逻辑。
由于Java层面的线程与操作系统的原生线程有对应的映射关系,如果要将一个线程进行阻塞或者唤醒都需要操作系统线程的协助,也就是从用户态到内核态的切换,这种相互之间的切换其实是一件非常消耗内存的事情。
所以JDK对于这种操作进行了很多的优化。
使用自旋锁,也就是说把线程进行阻塞操作之前让线程自旋等待一段时间,可能在等待的时候其他线程已经解锁了,这个时候就不需要线程在等待了,避免了用户态到内核态的切换。
在JDK中提供了三种不同的Monitor的实现,也就是三种不同的锁机制。
- 偏向锁
- 轻量级锁
- 重量级锁
这三种锁机制使得JDK对于synchronized的优化进行进一步的提升,当JVM检测到不同的资源竞争状况的时候,会自动切换到合适的锁实现机制,也就是所谓的锁的升级与降级。
当没有出现竞争的时候,默认使用的是偏向锁。
JVM会利用CAS操作,在对象头的MarkWord部分设置线程ID,以表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁,因为在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏向锁可以降低无竞争开销。
如果有一个线程试图锁定偏向锁对象的时候,JVM就撤销偏向锁,切换到轻量级锁。
轻量级锁通过CAS操作Mark Word来试图获取锁,如果重试成功,就使用普通的轻量级锁,否则就升级为重量级锁。
为什么说synchronized是非公平锁?
非公平主要表现在获取锁的行为上,并非按照申请锁的时间前后给等待线程分配锁,每当锁被释放之后,任何一个线程都有机会竞争到锁,这样做的目的是为了提高执行性能,缺点是会产生线饥饿现象。
什么是锁消除和锁粗化?
- 锁消除:指虚拟机及时编译器在运行时,对一些代码上要求同步,但被检测到不可能存在共享数据竞争的锁进行消除。主要根据逃逸分析。开发者怎么会在明知道不会存在数据竞争的情况下使用同步操作呢?很多的操作其实不是开发者自己加入的。
- 锁粗化:原则上,同步块的作用范围要尽量小。但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作在循环体内,频繁地进行互斥同步操作也会导致不必要的性能损耗。锁粗化就是增加锁的作用域。
为什么说 synchronized是一个悲观锁?乐观锁的实现原理又是什么?什么是CAS,它有什么特性?
synchronized是一个悲观锁,因为他的并发策略是悲观的,不管是否会产生竞争,任何的数据都必须要加锁、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要被唤醒等操作。
随着硬件指令集的发展,可以使用基于冲突检测的乐观锁并发策略。先进性操作,如果没有其他线程征用数据,那么就操作成功。
如果共享数据有被用到,产生了冲突,那就再进行其他的补偿措施。这种乐观的并发策略的许多实现不需要线程挂起,所以被称为非阻塞同步。
乐观锁的核心算法是CAS(Compareand Swap,比较交换),涉及到三个操作数:内存值、预期值、新值。当且仅当预期值和内存值相等的时候才将内存值修改新值。
这样处理的逻辑是,首先检查某块内存的值是否跟之前读取过的值一样,如果不一样则表示期间此内存值已经被别的线程修改过了,舍弃本次操作,否则则说明在此期间没有其他线程对此内存值进行修改,就可以直接使用该值。
CAS具有原子性,他的原子性有CPU硬件指令实现保证,即使用JNI调用Native方法调用C++编写的硬件指令,JDK中提供了Unsafe类执行这些操作。
乐观锁一定就是好的?
乐观锁避免了悲观锁独占对象的现象,同时也提高了并发性能,但它的缺点:
- 1、乐观锁只能保证一个共享变量的原子性操作,如果多一个或者几个变量,乐观锁就有点力不从心了,但互斥锁能轻易地解决该问题,不管对象数量多少以及对象大小。
- 2、长时间自旋操作可能导致开销较大,加入CAS长时间不成功而一直自旋,就会导致CPU消耗过大。
- 3、ABA问题,CAS的核心思想是比较交换,如果在过程中判断逻辑不够严谨,就会导致在一个线程将数据从A改成B,在另一个线程使用的时候,该线程又将数据改回了A,这样的时候对于另一个线程其实并没有感知到B值的存在。其实在整个过程中这个值是被修改过的。这种情况对于运算依赖比较大的场景影响比较大。解决的思路就是引入版本机制。
相关文章:
深入理解synchronized的原理是什么
对象头锁机制原则 Synchronized 的原理是什么 Synchronized 是由JVM实现的一种实现互斥同步的实现方式。如果查看synchronized关键字修饰的字节码,会发现在编译器生成了monitorenter和monitorexit两个字节码指令。 这两个指令的意思就是在虚拟机执行到monitore…...
Electron32-Vue3OS桌面管理os模板|vite5+electron32+arco后台os系统
原创新作electron32.xvue3arco.design仿ipad/windows桌面os系统。 基于最新跨平台技术Electron32、Vite5、Vue3 setup、Pinia2、Arco-Design、Echarts、Sortablejs实战开发桌面版osx管理系统。内置ipad/windows两种桌面风格模板、动态json配置桌面图标、自研栅格拖拽布局模板。…...
c++ 定义函数
在C中,定义函数是一个基本的编程概念。函数是执行特定任务的一段代码,可以接受参数并返回值。下面是关于如何定义和使用函数的详细介绍。 1. 函数的基本结构 函数的基本结构包括以下几个部分: 返回类型:表示函数返回值的类型。…...
【深度学习 计算机视觉】计算机视觉工程师所需的和有帮助的基本技能
计算机视觉工程师通常需要具备一系列的技术和非技术技能,以下是一些基本技能和知识领域,它们对于在这一领域取得成功非常有帮助: 技术技能 编程能力: 熟练掌握至少一种编程语言,如Python、C或Java。熟悉数据结构和算…...
【CSS】如何写渐变色文字并且有打光效果
效果如上,其实核心除了渐变色文字的设置 background: linear-gradient(270deg, #d2a742 94%, #f6e2a7 25%, #d5ab4a 48%, #f6e2a7 82%, #d1a641 4%);color: #e8bb2c;background-clip: text;color: transparent;还有就是打光效果,原理其实就是两块遮罩&am…...
Android 14(API 级别 34)中,DexClassLoader 不再支持可写 dex/jar 文件
Android 14(API 级别 34)中,DexClassLoader 不再支持从可写文件加载 dex/jar 文件。这意味着从Android 14开始,你不能再使用 DexClassLoader 来动态加载位于内部存储中的dex/jar文件,除非这些文件被设置为只读。 解决…...
Linux -动静态库
文章目录 1.文件系统1.1 inode1.2 硬链接定义特点使用方法 1.3软链接定义特点使用方法 2.动态库和静态库2.1动态库2.11定义与特点2.12使用方法 2.2 静态库2.21定义与特点2.22 使用方法 2.3示例2.31编写库代码2.32编译生成动态库2.33 编译生成静态库 2.4总结 1.文件系统 我们使…...
原点安全荣获“AutoSec Awards 安全之星”优秀汽车数据安全合规方案奖
9月3日,「AutoSec 2024第八届中国汽车网络安全周暨第五届智能汽车数据安全展」在上海盛大开幕。本届大会由谈思实验室和谈思汽车主办、上海市车联网协会联合主办,以汽车“网络数据安全、软件安全、功能安全”为主题,汇聚了国内外的技术专家、…...
2024前端面试题分享
前言 最近忙着面试很久没有更新文章了,分享一下我收集的前端面经,当然题目仅供参考(乞求秋招offer) 面试题 响应式布局 ---根据用户的的窗口变化而变化的布局方式 react 的hooks ---官方提供的钩子和自定义的钩子…...
数学基础 -- 线性代数之正交矩阵
正交矩阵 正交矩阵是线性代数中的一个重要概念,具有许多优良的性质,在数值计算、线性变换、信号处理等领域有着广泛的应用。 1. 正交矩阵的定义 一个 n n n \times n nn 的方阵 Q Q Q 如果满足以下条件: Q T Q Q Q T I Q^T Q Q Q^T …...
PostgreSQL 17即将发布,新功能Top 3
按照计划,PostgreSQL 17 即将在 2024 年 9 月 26 日发布,目前已经发布了第一个 RC 版本,新版本的功能增强可以参考 Release Notes。 本文给大家分享其中 3 个重大的新增功能。 MERGE 语句增强 MERGE 语句是 PostgreSQL 15 增加的一个新功能…...
心觉:别再做单线程的打工人!换个思路突破
Hi,我是心觉,与你一起玩转潜意识、脑波音乐和吸引力法则,轻松搞定人生挑战,实现心中梦想! 挑战日更写作161/1000(完整记录在下面) 公门洞开纳百川 众心逐梦越千山 号召引领潜力绽 心觉潜意识无间 想让财富翻个2倍…...
深度学习-用神经网络NN实现足球大小球数据分析软件
文章目录 前言一、 数据收集1.1特征数据收集代码实例 二、数据预处理清洗数据特征工程: 三、特征提取四、模型构建五、模型训练与评估总结 前言 预测足球比赛走地大小球(即比赛过程中进球总数是否超过某个预设值)的深度学习模型是一个复杂但有…...
linux 9系统分区扩容
1.可以看到我的是9.2的系统,系统分区:/dev/mapper/rl-root 83G 8.0G 75G 10% / 2.接下来,我们新增一块新的硬盘,而不是直接对这个硬盘的基础上再扩容。 关机,加30G硬盘,再开机 fdisk -l fdisk /dev/…...
Solidity初体验
一、概念知识 什么是智能合约? 智能合约是仅在满足特定条件时才在区块链上部署和执行的功能,无需任何第三方参与。 由于智能合约本质上是不可变的和分布式的,因此它们在编写和部署后无法修改或更新。此外,分布式的意义在于任何…...
大模型笔记01--基于ollama和open-webui快速部署chatgpt
大模型笔记01--基于ollama和open-webui快速部署chatgpt 介绍部署&测试安装ollama运行open-webui测试 注意事项说明 介绍 近年来AI大模型得到快速发展,各种大模型如雨后春笋一样涌出,逐步融入各行各业。与之相关的各类开源大模型系统工具也得到了快速…...
html前段小知识点
1. 什么是HTML? 超文本标记语言是一种 用于创建网页的标准标记语言 HTML 文档包含了HTML 标签及文本内容 也叫文档1.什么是css? CSS (层叠样式表),是一种用来为结构化文档添加样式的计算机语言,CSS 文件扩展名为 .css。 可以设…...
AD7606工作原理以及FPGA控制验证(串行和并行模式)
文章目录 一、AD7606介绍二、AD7606采集原理2.1 AD7606功能框图2.2 AD7606管脚说明 三、AD7606并行模式时序分析以及实现3.1 并行模式时序图3.2 并行模式时序要求3.3 代码编写3.4 仿真观察 四、AD7606串行模式时序分析以及实现4.1 串行模式时序图4.2 串行模式时序要求4.3 代码编…...
如何查看Pod的Container资源占用情况
云原生学习路线导航页(持续更新中) 方法一:直接查看pod的资源占用 kubectl top pods ${pod-name} -n ${ns} 方法二:通过运行的进程,查看pod的某个容器资源占用 1.找到pod所在node容器号:kubectl descri…...
WordPress上可以内容替换的插件
插件下载地址:WordPress内容替换插件 – 果果开发 类型 替换的类型:文章、自定义文章类型、分类、标签、媒体库、页面、评论、数据库表,不同的类型可以替换不同的字段。 替换字段 替换的字段,哪些字段内容需要替换。除了数据库…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
uni-app学习笔记三十五--扩展组件的安装和使用
由于内置组件不能满足日常开发需要,uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件,需要安装才能使用。 一、安装扩展插件 安装方法: 1.访问uniapp官方文档组件部分:组件使用的入门教程 | uni-app官网 点击左侧…...
