当前位置: 首页 > news >正文

【Java并发编程】线程安全(一)Synchronized原理

Synchronized底层实现

简单来说,Synchronized关键字的执行主体是线程对象,加锁是通过一个锁对象来完成的是,而锁对象底层关联了一个c++源码的monitor的对象,monitor对象底层又对应了操作系统级别的互斥锁,同一时刻只有一个线程能够持有这把锁

Synchronized底层依赖于jvm的monitorenter和monitorexit两个指令,这两个指令用于获取锁和释放锁
请添加图片描述

锁对象结构与sync锁升级的概念

多个线程争抢锁的时候,其实就像是在争抢锁对象,前面提到锁对象底层关联了一个monitor的对象,最终关联操作系统级别的互斥锁,这种情况其实属于申请系统空间的重量级锁,是需要完成系统调用的,因此存在性能问题。

Synchronized自身有一个锁升级的概念:在低并发的情况下先申请用户空间的锁,而不会申请系统空间的锁,也就不涉及用户内核态切换

理解锁升级,首先需要关注Java对象在内存中的存储布局,内部有一个mark-word字段是实现锁升级的关键:

请添加图片描述

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)实例数据(Instance Data)对齐填充(Padding)

对象头内部有一个64bit的mark-word标记字段,后面的三位代表了当前锁对象对应哪种锁:

  • 00:轻量锁
  • 10:重量锁
  • 11:GC标记

(由于2bit不够表示5种锁类型,所以又借了前面一位)

  • 001:无锁
  • 101:轻量级锁

锁升级过程:

  1. 无锁的情况下,第一个线程尝试获得偏向锁:尝试给对象头mark word字段指向的thread id用CAS操作替换成自己的,成功了就直接获得偏向锁
  2. 如果CAS操作失败,意味着同时有多个线程抢锁,这时会在抢到锁的线程到达安全点的时候,将锁升级为轻量级锁,具体操作:拷贝mark word到lock record中,放入到所有抢锁线程的栈中,并且mark word会有指针指向当前占用的锁线程的lock record。其他抢锁的线程利用CAS操作多次自旋,尝试将mark word中的指针指向自己的lock record
  3. 自旋到一定次数升级为重量级锁,抢锁失败的线程进入阻塞状态,这时mark word中的指针将指向对象关联的monitor对象,monitor结构如下:
ObjectMonitor::ObjectMonitor() {  _header       = NULL;  _count       = 0;  _waiters      = 0,  _recursions   = 0;       //线程的重入次数_object       = NULL;  _owner        = NULL;    //标识拥有该monitor的线程_WaitSet      = NULL;    //等待线程组成的双向循环链表,_WaitSet是第一个节点_WaitSetLock  = 0 ;  _Responsible  = NULL ;  _succ         = NULL ;  _cxq          = NULL ;    //多线程竞争锁进入时的单向链表FreeNext      = NULL ;  _EntryList    = NULL ;    //_owner从该双向循环链表中唤醒线程结点,_EntryList是第一个节点_SpinFreq     = 0 ;  _SpinClock    = 0 ;  OwnerIsThread = 0 ;  
}

owner属性指向抢锁成功的线程,count记录重入个数。另外还会有入口集entrySet和等待集waitset。

ReentrantLock和Synchronized的选择

这是一个经常被提到的问题

实际上Java发展的过程中对Synchronized的性能做了优化,比如锁升级机制,所以性能上synchronized并不差。

  • 考虑使用ReentrantLock的理由:

主要在一些Synchronized内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具

例如,Synchronized具有块结构的特性,即都是在方法/代码块开始是获取,方法/代码块结束时生效。

而ReentrantLock具有非块结构的特性,像下面这种实现就只能使用ReentrantLock

private ReentrantLock lock;public void foo() {...lock.lock();...
}public void bar() {...lock.unlock();...
}

总之,ReentrantLock具备一些高级功能,包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。

  • 考虑使用Synchronized的理由:

与ReentrantLock相比,内置锁的一个优点是:能给出在哪些线程调用帧中获得了哪些锁,并能够检测和识别发生死锁的线程。JVM并不知道哪些线程持有ReentrantLock,因此在调试使用ReentrantLock的线程的问题时,将起不到帮助作用。

ReentrantLock的非块结构特性仍然意味着,获取锁的操作不能与特定的栈帧关联起来,而内置锁却可以。

未来更可能会提升synchronized而不是ReentrantLock的性能。因为synchronized是JVM的内置属性,它能执行一些优化,例如对线程封闭的锁对象的锁消除优化,通过增加锁的粒度来消除内置锁的同步,而如果通过基于类库的锁来实现这些功能,则可能性不大。

相关文章:

【Java并发编程】线程安全(一)Synchronized原理

Synchronized底层实现 简单来说,Synchronized关键字的执行主体是线程对象,加锁是通过一个锁对象来完成的是,而锁对象底层关联了一个c源码的monitor的对象,monitor对象底层又对应了操作系统级别的互斥锁,同一时刻只有一…...

[apollo]vue3.x中apollo的使用

[apollo]vue3.x中apollo的使用通过客户端获取Apollo配置环境工具的安装获取Apollo配置相关代码错误提示Uncaught (in promise) Error: Apollo client with id default not found. Use provideApolloClient() if you are outside of a component setup通过开放接口获取Apollo配置…...

system()函数启用新进程占有原进程的文件描述符表的问题

我在A程序中占用了/dev/video0这个独占模式的设备文件,在A中用system函数启用了B程序,B程序的代码中并不包含对/dev/video0的访问,但是我发现B程序也占用了/dev/video0,并且我在A程序中关闭了/dev/video0后,A程序不再占…...

nignx(安装,正反代理,安装tomcat设置反向代理,ip透传)

1安装nginx 安装wget Yum install -y wget 下载(链接从官网找到右键获取) 以下过程root 安装gcc Yum -y install gcc c 安装pcre Yum install -y pcre pcre-devel Openssl Yum install -y openssl openssl-devel 安装zlib Yum install -y zlib zlib-devel 安装make Yum inst…...

sklearn模块常用内容解析笔记

文章目录 回归模型评价指标R2_score预备知识R2_score计算公式r2_score使用方法注意事项参考文献回归模型评价指标R2_score 回归模型的性能的评价指标主要有:RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时,RMSE、MAE、MSE难以衡量模…...

我的 System Verilog 学习记录(2)

引言 从本文开始,就开始系统学习 System Verilog ,不只是语法,还有结合 Questa Sim 的实际编程练习、Debug。 本文简单介绍 System Verilog 语言的用途以及学习的必要性。 前文链接: 我的 System Verilog 学习记录&#xff08…...

【调研报告】Monorepo 和 Multirepo 的风格对比及使用示例

带有权重的Monorepo和Multirepo对比 功能/特性MonorepoMultirepoMonorepo权重值Multirepo权重值代码管理管理多个代码库更加复杂管理单个代码库更加简单37依赖管理可以简化依赖管理依赖冲突可能会更加困难73构建和部署构建和部署更加容易构建和部署可能需要更多的配置82团队协…...

Retrofit源码分析

文章目录一、简介二、源码分析2.1Retrofit的本质流程2.2源码分析2.2.1 创建Retrofit实例步骤1步骤2步骤3步骤4步骤5总结2.2.2创建网络请求接口的实例外观模式 & 代理模式1.外观模式2. 代理模式步骤3步骤4总结2.2.3执行网络请求同步请求OkHttpCall.execute()1.发送请求过程2…...

Mybatis-Plus入门系列(20) -兼容多种数据库

有道无术,术尚可求,有术无道,止于术。 文章目录前言方案分析1. 分页2. XML自定义SQL案例演示1. 配置2. 简单分页查询3. 带方言的分页查询参考前言 在我们实际开发软件产品过程中,数据库的类型可能不是确定的,也有客户…...

JetPack板块—Android X解析

Android Jetpack简述 AndroidX 是Android团队用于在Jetpack中开发,测试,打包,发布和版本管理的开源项目。相比于原来的Android Support库,AndroidX 可以称得上是一次重大的升级改进。 和Support库一样,AndroidX与Android 操作系…...

C++学习笔记-数字

当我们使用数字时,通常我们使用原始数据类型,例如 int,short,long,float 和 double 等。数字数据类型,它们的可能值和取值范围在讨论 C 数据类型时已经解释了。 C 定义数字 我们已经在之前笔记的各种实例…...

Nginx——Nginx的基础原理

摘要 Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器,是一个高性能的HTTP和反向代理服务器,同时也是一个 IMAP/POP3/SMTP 代理服务器。Nginx 是由俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,它已经在该站点运行超过两年半了。…...

服务端开发Java之备战秋招面试篇1

在这个面试造火箭工作拧螺丝的时代背景下,感觉不是很好,不过还好也是拿到了还行的offer,准备去实习了,接下来就是边实习边准备秋招了,这半年把(技术栈八股文面经算法题项目)吃透,希望…...

【C++的OpenCV】第三课-OpenCV图像加载和显示

我们开始学习OpenCV一、OpenCV加载图片和显示图片1.1 imread()函数的介绍1.2 cv::namedWindow()函数的介绍1.4 imshow()函数介绍1.5 Mat容器介绍二、 代码实例(带注释)2.1 代码2.2 执行结果一、OpenCV加载图片和显示图片 本章节中,将会学习到…...

【面试1v1实景模拟】Spring事务 一文到底

老面👴:小伙子,了解Spring的事务吗? 解读🔔:这个必须了解,不了解直接挂~😂😂😂,但面试官肯定不是想听你了解两个字,他是想让你简单的介绍下。 笑小枫🍁:了解,事务在逻辑上是一组操作,要么执行,要不都不执行。主要是针对数据库而言的,比如说 MySQL。为…...

Neuron Selectivity Transfer 原理与代码解析

paper:Like What You Like: Knowledge Distill via Neuron Selectivity Transfercode:https://github.com/megvii-research/mdistiller/blob/master/mdistiller/distillers/NST.py本文的创新点本文探索了一种新型的知识 - 神经元的选择性知识&#xff0c…...

vue项目关闭子页面,并更新父页面的数据

今天下午是一个非常痛苦的,想要实现一个功能: 父页面打开了一个新的页面(浏览器打开一个新的窗口),并在子页面提交数据之后,父页面的数据要同步更新。 难点:父页面是一个表格列表,…...

第五次作业:修改redis的配置文件使得windows的图形界面客户端可以连接redis服务器

1. 安装 Redis 依赖 Redis 是基于 C语言编写的,因此首先需要安装 Redis 所需要的 gcc 依赖: yum install -y gcc tcl 2、上传安装文件 将下载好的 redis-6.2.7.tar.gz 安装包上传到虚拟机的任意目录(一般推荐上传到 /usr/local/src目录&am…...

【11】FreeRTOS的延时函数

目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍 函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对…...

Vue页面组成及常用属性

一、Vue页面组成 目前的项目中,Vue页面都是采用组件套娃的形式,由一个一个的组件拼接而成整个页面。一个组件就是一个.vue文件。组件通常由template和script两部分组成: template部分:页面展示的具体元素内容,比如文字…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage)&#xff1a…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...