并发编程-Synchronized
什么是Synchronized
synchronized是Java提供的一个关键字,Synchronized可以保证并发程序的原子性,可见性,有序性。
我们会把synchronized称为重量级锁。主要原因,是因为JDK1.6之前,synchronized是一个重量级锁相比于JUC的锁显得非常笨重,存在性能问题。JDK1.6及之后,Java对synchronized进行的了一系列优化,性能与JUC的锁不相上下。
Synchronized 使用
synchronized可以修饰方法和代码块
方法:可修饰静态方法和非静态方法
代码块:同步代码块的锁对象可以为当前实例对象、字节码对象(class)、其他实例对象
1 修饰方法普通方法
synchronized修饰普通方法,锁对象默认为this
2 修饰静态方法
锁对象为Class对象
3 代码块
synchronized (lockobj) {// 书写同步代码
}
Synchronized原理分析
public class Demo {Object lock = new Object();public synchronized void demo() {}public void execute() {synchronized (lock) {System.out.println("get lock");}}
}
javac Demo.java
javap -c Demo.class
public synchronized void syncMethod();Code:0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #5 // String get lock5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnpublic void executeMethod();Code:0: aload_01: getfield #3 // Field lock:Ljava/lang/Object;4: dup5: astore_16: monitorenter7: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;10: ldc #5 // String get lock12: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V15: aload_116: monitorexit17: goto 2520: astore_221: aload_122: monitorexit23: aload_224: athrow25: return
从上述字节码指令看的到,同步代码块和同步方法的字节码是不同的:
对于synchronized同步块
,对应的monitorenter和monitorexit指令分别对应synchronized同步块的进入和退出。
为什么会多一个monitorexit?编译器会为同步块添加一个隐式的try-finally,在finally中会调用monitorexit命令释放锁
对于synchronized方法
,对应ACC_SYNCHRONIZED关键字,JVM进行方法调用时,发现调用的方
法被ACC_SYNCHRONIZED修饰,则会先尝试获得锁,方法调用结束了释放锁。在JVM底层,对于这两种synchronized的实现大致相同。都是基于monitorenter和monitorexit指令实现,底层还是使用 标记字段MarkWord和Monitor(管程)来实现重量级锁。
什么是管程?
Monitor中文翻译为管程,也有人称之为“监视器”,管程指的是管理共享变量以及对共享变量的操作过程,让他们支持并发。
Java中的所有对象都可以作为锁,每个对象都与一个 monitor 相关联,线程可以对 monitor 执行lock 和 unlock 操作。
Java并没有把lock和unlock操作直接开放给用户使用,但是却提供了两个指令来隐式地使用这两个操作:moniterenter和moniterexit。moniterenter对应lock操作,moniterexit对应unlock操作,通过这两个指锁定和解锁 monitor 对象来实现同步。
当一个monitor对象被线程持有后,它将处于锁定状态。对于一个 monitor 而言,同时只能有一个线程能锁定monitor,其它线程试图获得已被锁定的 monitor时,都将被阻塞。当monitor被释放后,阻塞中的线程会尝试获得该 monitor锁。一个线程可以对一个 monitor 反复执行 lock 操作,对应的释放锁时,需要执行相同次数的 unlock 操作。
管程相关文档:
https://www.cnblogs.com/binarylei/p/12544002.html#2-%E7%AE%A1%E7%A8%8Bmonitor
Synchronized锁升级
在JDK1.6之后同步锁一共有四种状态,级别从低到高依次是:无锁,偏向锁,轻量级锁,重量级锁。这四种状态
会随着竞争激烈情况逐渐升级。
偏向锁(需要运行时间在5-6s以上JVM才会开启)
只有一个线程访问锁资源(无竞争)的话,偏向锁就会把整个同步措施都消除,并记录当前持有锁资源的线程和锁的型。
轻量级锁
轻量级锁是基于这样一个想法:只有两个线程交替运行时,如果线程竞争锁失败了,先不立即挂起,而是让它飞一会儿(自旋),在等待过程中,可能锁就被释放了,这时该线程就可以重新尝试获取锁,同时记录持有锁资源的线程和锁的类型。
有关锁的信息都是object对象头中markdown来保存的
锁升级过程演示:
对象头怎么看每一位的含义可以看这篇博客
public class Demo {public static void main(String[] args) throws InterruptedException {// 为了开启偏向锁Thread.sleep(5001);Object lock = new Object();// 偏向锁 110printObj(lock, 1);// 都在main线程里面所以还是偏向锁synchronized (lock) {printObj(lock, 2);}// 再开一个线程进行资源争抢new Thread(() -> {synchronized (lock) {System.out.println("get lock one");// 升级成为了轻量级锁 00printObj(lock, 3);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}).start();// 再开一个线程进行资源争抢new Thread(() -> {synchronized (lock) {System.out.println("get lock two");}}).start();// 少量竞争轻量级锁 00printObj(lock, 4);// 让上面的线程结束 然后开始疯狂竞争// 竞争非常的激烈会升级成重量级锁 10Thread.sleep(2000);for (int i = 0; i < 10; i ++) {new Thread(() -> {synchronized (lock) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("get lock three");}}).start();}printObj(lock, 5);}static void printObj(Object o, int i) {String s = ClassLayout.parseInstance(o).toPrintable();System.out.println(s + " " + i);}
}
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total1
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 d8 aa 05 (00000101 11011000 10101010 00000101) (95082501)4 4 (object header) e4 01 00 00 (11100100 00000001 00000000 00000000) (484)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total2
get lock one
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) c8 ed 5f ad (11001000 11101101 01011111 10101101) (-1386222136)4 4 (object header) b5 00 00 00 (10110101 00000000 00000000 00000000) (181)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total3
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) c8 ed 5f ad (11001000 11101101 01011111 10101101) (-1386222136)4 4 (object header) b5 00 00 00 (10110101 00000000 00000000 00000000) (181)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total4
get lock two
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) ba 71 b5 05 (10111010 01110001 10110101 00000101) (95777210)4 4 (object header) e4 01 00 00 (11100100 00000001 00000000 00000000) (484)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total5
相关文章:

并发编程-Synchronized
什么是Synchronized synchronized是Java提供的一个关键字,Synchronized可以保证并发程序的原子性,可见性,有序性。 我们会把synchronized称为重量级锁。主要原因,是因为JDK1.6之前,synchronized是一个重量级锁相比于J…...

C语言——从头开始——深入理解指针(1)
一.内存和地址 我们知道计算上CPU(中央处理器)在处理数据的时候,是通过地址总线把需要的数据从内存中读取的,后通过数据总线把处理后的数据放回内存中。如下图所示: 计算机把内存划分为⼀个个的内存单元,每…...

微信小程序-绑定数据并在后台获取它
如图 遍历列表的过程中需要绑定数据,点击时候需要绑定数据 这里是源代码 <block wx:for"{{productList}}" wx:key"productId"><view class"product-item" bindtap"handleProductClick" data-product-id"{{i…...
【删除数组用delete和Vue.delete有什么区别】
删除数组用delete和Vue.delete有什么区别? 在 JavaScript 中,delete 和 Vue.js 中的 Vue.delete 是两个完全不同的概念,它们在删除数组元素时的作用和效果也有所不同。 JavaScript 中的 delete 关键字: 在原生 JavaScript 中&a…...
【QT+QGIS跨平台编译】之四十二:【QWT+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
文章目录 一、QWT介绍二、QWT下载三、文件分析四、pro文件五、编译实践5.1 Windows下编译4.2 Linux下编译5.3 MacOS下编译一、QWT介绍 QWT是一个基于Qt框架的开源C++库,用于创建交互式的图形用户界面。它提供了丰富的绘图和交互功能,可以用于快速开发图形化应用程序。 QWT包…...
yum方式快速安装mysql
问题描述 使用yum的方式简单安装了一下mysql,对过程进行简单记录。 步骤 ①安装wget和vim sudo yum -y install wget vim②下载mysql的rpm包 sudo wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm③升级和更新rpm包 sudo rpm -Uv…...
基于Java的家政预约管理平台
功能介绍 平台采用B/S结构,后端采用主流的Springboot框架进行开发,前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括:首页、家政详情、家政入驻、用户中心模块。后台功能包括:家政管理、分类管理…...

C语言前世今生
C语言前世今生 C语言的发展历史 C语言于1972年11月问世,1978年美国电话电报公司(AT&T)贝尔实验室正式发布C语言,1983年由美国国家标准局(American National Standards Institute,简称ANSI)…...
android aidl进程间通信封装通用实现-用法说明
接上一篇:android aidl进程间通信封装通用实现-CSDN博客 该aar包的使用还是比较方便的 一先看客户端 1 初始化 JsonProtocolManager.getInstance().init(mContext, "com.autoaidl.jsonprotocol"); //客户端监听事件实现 JsonProtocolManager.getInsta…...
【Java中23种设计模式-单例模式2--懒汉式线程不安全】
加油,新时代打工人! 今天,重新回顾一下设计模式,我们一起变强,变秃。哈哈。 23种设计模式定义介绍 Java中23种设计模式-单例模式 package mode;/*** author wenhao* date 2024/02/19 09:16* description 单例模式--懒…...

【后端高频面试题--Linux篇】
🚀 作者 :“码上有前” 🚀 文章简介 :后端高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 后端高频面试题--Linux篇 往期精彩内容Windows和Linux的区别?Unix和Linux有什么区别…...

网络原理HTTP/HTTPS(2)
文章目录 HTTP响应状态码200 OK3xx 表示重定向4xx5xx状态码小结 HTTPSHTTPS的加密对称加密非对称加密 HTTP响应状态码 状态码表⽰访问⼀个⻚⾯的结果.(是访问成功,还是失败,还是其他的⼀些情况…).以下为常见的状态码. 200 OK 这是⼀个最常⻅的状态码,表⽰访问成功 2xx都表示…...

【Java中23种设计模式-单例模式2--懒汉式2线程安全】
加油,新时代打工人! 简单粗暴,学习Java设计模式。 23种设计模式定义介绍 Java中23种设计模式-单例模式 Java中23种设计模式-单例模式2–懒汉式线程不安全 package mode;/*** author wenhao* date 2024/02/19 09:38* description 单例模式…...

由LeetCode541引发的java数组和字符串的转换问题
起因是今天在刷下面这个力扣题时的一个报错 541. 反转字符串 II - 力扣(LeetCode) 这个题目本身是比较简单的,所以就不讲具体思路了。问题出在最后方法的返回值处,要将字符数组转化为字符串,第一次写的时候也没思考直…...
HTTP 头部- Origin Referer
Origin & Referer Origin Header 示例 Origin 请求头部是一个 HTTP 头部,它提供了发起请求的网页的源(协议、域名和端口)信息。它通常在进行跨域资源共享(CORS)请求时使用,以便服务器可以决定是否接受…...
Python 实现Excel 文件合并
Excel 文件合并方法较多,前面文章有通过Uipath RPA 对文件进行合并,也可以通过Python或VBA写脚本合并。 通常写脚本维护性更加简洁,本文提供Python 脚本对Excel 文件进行合并,参考Uipath 调用Python 文章,Uipath 调用Python 脚本程序详解-CSDN博客 便能快速实现。代码如…...
ECMAScript 6+ 新特性 ( 一 )
2.1.let关键字 为了解决之前版本中 var 关键字存在存在着越域, 重复声明等多种问题, 在 ES6 以后推出 let 这个新的关键字用来定义变量 //声明变量 let a; let b,c,d; let e 100; let f 123, g hello javascript, h [];let 关键字用来声明变量,使用 let 声明的…...
动态DP入门线性动态DP
动态DP入门&线性动态DP 前言核心思想例1例22024牛客寒假4K2022牛客寒假2J结论 前言 OI-WiKi上有一个动态DP讲解,直接讲到了树型DP领域,同时需要树链剖分,门槛有点高。本文针对线性DP做一个动态DP的讲解。 首先当然要懂得一定的DP的相关…...
基于python+django+vue.js开发的停车管理系统
功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。 功能包括:车位管理、会员管理、停车场管理、违规管理、用户管理、日志管理、系统信息模块。 源码地址 https://github.com/geeeeeeeek/pytho…...

网站管理新利器:免费在线生成 robots.txt 文件!
🤖 探索网站管理新利器:免费在线生成 robots.txt 文件! 你是否曾为搜索引擎爬虫而烦恼?现在,我们推出全新的在线 robots.txt 文件生成工具,让你轻松管理网站爬虫访问权限,提升网站的可搜索性和…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)
漏洞概述 漏洞名称:Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号:CVE-2023-25194 CVSS评分:8.8 影响版本:Apache Kafka 2.3.0 - 3.3.2 修复版本:≥ 3.4.0 漏洞类型:反序列化导致的远程代…...

Centos 7 服务器部署多网站
一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站,目录结构如下: bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...