synchronized基础篇

news2025/10/20 3:06:40

之前我们已经通过3篇文章由浅到深的分析了synchronized的用法和原理:

  • synchronized的基础:synchronized都问啥?
  • 偏向锁升级到轻量级锁:从源码揭秘偏向锁的升级
  • 轻量级锁升级到重量级锁:什么是synchronized的重量级锁

还有一篇是关于并发控制中常用锁的设计一文看懂并发编程中的锁。可以说是从设计,到用法,再到实现原理,对synchronized进行了全方位的剖析。今天我们就用之前学习的内容解答一些热点题目。

Tips:标题是“抄袭”《一年一度喜剧大赛》作品《梦幻丽莎发廊》的台词。由仁科,茂涛,蒋龙,蒋诗萌和欧剑宇表演,爆笑推荐。

synchronized基础篇

基础篇的问题主要集中在synchronized的用法上。例如:

  1. synchronized锁.class对象,代表着什么?
  2. synchronized什么情况下是对象锁?什么情况下是类锁?
  3. 如果对象的多个方法添加了synchronized,那么对象有几把锁?

很多小伙伴解答这类问题时喜欢背诸如“synchronized修饰静态方法,作用的范围是整个静态方法,作用对象是这个类的所有对象”这种,相当于直接背结论,忽略了原理。

先来回顾下synchronized都问啥?中提到的原理:Java中每个对象都与一个监视器关联。synchronized锁定与对象关联的监视器(可以理解为锁定对象本身),锁定成功后才可以继续执行

举个例子:

public class Human {
	public static synchronized void run() {
		// 业务逻辑
	}
}

synchronized修饰静态方法,而静态方法是类所有,可以理解为synchronized锁定了Human.class对象,接下来我们推导现象。

假设线程t1执行run方法且尚未结束,即t1锁定了Human.class,且尚未释放,那么此时所有试图锁定Human.class的线程都会被阻塞。

例如,线程t2执行run方法会被阻塞:

Thread t2 = new Thread(Human::run);
t2.start();

如果我们添加如下方法呢?

public synchronized void eat() {
	// 业务逻辑  
}

synchronized修饰实例方法,属于对象所有,可以理解为synchronized锁定了当前对象。执行以下测试代码,会发生阻塞吗?

new Thread(Human::run, "t1")).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
	Human human = new Human();
	human.eat();  
}, "t2")).start();

答案是不会,因为t1锁定的是Human.class对象,而t2锁定的是Human的实例对象,它们之间不存在任何竞争。

再添加一个方法,并执行如下测试,会发生阻塞吗?

public static synchronized void walk() {
	// 业务逻辑
}  

public static void main(String[] args) throws InterruptedException {
	new Thread(Human::run, "t1").start();
	TimeUnit.SECONDS.sleep(1);
	new Thread(Human::walk, "t2").start();  
}

答案是线程t2会阻塞,因为线程t1和线程t2在竞争同一个Human.class对象,而很明显线程t1会抢先锁定Human.class对象。

最后再做一个测试,添加如下方法和测试代码:

public synchronized void drink() {
	// 业务逻辑
}

public static void main(String[] args) throws InterruptedException {
	Human human = new Human();
	new Thread(human::eat, "t1").start();
	TimeUnit.SECONDS.sleep(1);
	new Thread(human::drink, "t2").start();
	new Thread(()-> {
		Human t3 = new Human();
		t3.eat();
	}, "t3").start();

	TimeUnit.SECONDS.sleep(1);
	new Thread(()-> {
		Human t4 = new Human();
		t4.eat();
	}, "t4").start();
}

小伙伴们可以按照用法结合原理的方式,推导这段代码的运行结果。

Tips:业务逻辑可以执行TimeUnit.SECONDS.sleep(60)模拟长期持有。

synchronized进阶篇

进阶篇则主要考察synchronized的原理,例如:

  • synchronized是如何保证原子性,有序性和可见性的?
  • 详细描述synchronized的原理和锁升级的过程。
  • 什么说synchronized是悲观锁/非公平锁/可重入锁?

synchronized的并发保证

假设有如下代码:

private static int count = 0;
public static synchronized void add() {
	......
	count++;
	......
}

在正确同步的前提下,同一时间有且仅有一个线程能够执行add方法,对count进行修改。

此时便“营造”了一种单线程环境,而编译器对重排序做出了“as-if-serial”的保证,因此不会存在有序性问题。同样的,仅有一个线程执行count++,那么也不存在原子性问题

至于可见性,我们在什么是synchronized的重量级锁中释放重量级锁的部分看到了storeload内存屏障,该屏障保证了写操作的数据对下一读操作可见。

Tips

  • synchronized并没有禁止重排序,而是“营造”了单线程环境;
  • 内存屏障我们在volatile中重点解释。

synchronized的实现原理

synchronized是JVM根据管程的设计思想实现的互斥锁。synchronized修饰代码块时,编译后会添加monitorenter和monitorexit指令,修饰方法时,会添加ACC_SYNCHRONIZED访问标识。

Java 1.6之后,synchronized的内部结构实际上分为偏向锁,轻量级锁和重量级锁3部分。

当线程进入synchronized方法后,且未发生竞争,会修改对象头中偏向的线程ID,此时synchronized处于偏向锁状态。

当产生轻微竞争后(常见于线程交替执行),会升级(膨胀)到轻量级锁的状态。

当产生激烈竞争后,轻量级锁会升级(膨胀)到重量级锁,此时只有一个线程可以获取到对象的监视器,其余线程会被park(暂停)且进入等待队列,等待唤醒。

synchronized的特性实现

为什么说synchronized是悲观锁?来回顾下一文看懂并发编程中的锁中提到的悲观锁,悲观锁认为并发访问共享总是会发生修改,因此在进入临界区前一定会执行加锁操作

那么对于synchronized来说,无论是偏向锁,轻量级锁还是重量级锁,使用synchronized总是会发生加锁,因此是悲观锁。

为什么说synchronized是非公平锁?接着回顾下非公平锁,非公平性体现在发生阻塞后的唤醒并不是按照先来后到的顺序进行的

在synchronized中,默认策略是将cxq队列中的数据移入到EntryList后再进行唤醒,并没有按照先后顺序执行。实际上我们也不知道cxq和EntryList中的线程到底谁先进入等待的。

为什么说synchronized是可重入锁?回顾下可重入锁,可重入指的是允许同一个线程反复多次加锁

使用上,synchronized允许同一个线程多次进入。底层实现上,synchronized内部维护了计数器_recursions,发生重入时,计数器+1,退出时计数器-1。

通过_recursions的命名,我们也能知道Java中的可重入锁就是POSIX中的递归锁。

结语

本文的内容比较简单,主要是根据之前的内容回答一些热点问题。不说是做到学以致用,至少做到学习后,能回答一些面试问题。

当然更深层次的意义,在于指导我们合理的使用synchronized以及我们可以从中借鉴到的设计思想。


如果本文对你有帮助的话,还请多多点赞支持。如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核Java技术的金融摸鱼侠王有志,我们下次再见!

 

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

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

相关文章

战略文化派,战略形成是集体信念和愿景形成的过程

战略文化派:战略形成是集体信念和愿景形成的过程 趣讲大白话:在乎集体认同 【趣讲信息科技271期】 **************************** 关于企业文化的故事很多 比如:中国海尔砸冰箱后蜕变的文化 比如:日本的稻盛和夫倡导的东方利他文化…

Nacos安装

Windows安装 下载安装包 在Nacos的GitHub页面https://github.com/alibaba/nacos/releases,下载安装包 解压 将这个包解压到任意非中文目录下 目录说明: bin:启动脚本 conf:配置文件 配置 配置文件路径 默认端口为8848 启…

ResNet详解:网络结构解读与PyTorch实现教程

目录 一、深度残差网络(Deep Residual Networks)简介深度学习与网络深度的挑战残差学习的提出为什么ResNet有效? 二、深度学习与梯度消失问题梯度消失问题定义为什么会出现梯度消失?激活函数初始化方法网络深度 如何解决梯度消失问…

新KG视点 | Jeff Pan、陈矫彦等——大语言模型与知识图谱的机遇与挑战

OpenKG 大模型专辑 导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力,知识图谱则丰富了表示知识的方式,两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下,OpenKG组织…

HDU 1911 Showstopper 二分搜素

一、题目翻译 如果没有发现细微的形式,那么对大量数据集合进行数据挖掘是一件痛苦而又长时间的过程。 一家公司的某个软件成对的使用组件生成了大量的数据对象,因为是成对使用,所以每个数据对象出现的次数一定为偶数次,但是在多…

学生成绩管理系统【控制台+MySQL】(Java课设)

系统类型 控制台类型Mysql数据库存储数据 使用范围 适合作为Java课设!!! 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址:https://download.csdn.net/download/qq_50954361/87738977 更多系统资源库地…

验收测试怎么做?需要怎么配合

验收测试的流程,是验证系统是否达到了用户需求规格说明书(可能包括项目或产品验收准则)中的要求,测试试图尽可能地发现软件中存留的缺陷,从而为软件进一步改善提供帮助,并保证系统或软件产品Z终被用户接受。…

如何用 QGIS 下载高清天地图影像机,同时解决下载质量差的问题!

使用 QGIS 我们可以获得下面这种图像,既有大范围,又有更高的细节(地图级别),基本上把整个苏州市中心城区的建筑物都囊括进去了。 还可以下载大范围、高清晰度的各种在线卫星底图服务的影像,比如大面积的哨兵2影像,但国外的服务器一般都很烂,不可能是电信、移动的问题,…

Python环境下载安装使用

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

03.OA项目之我的会议(查询会议排座送审)

目录 会议查询 会议排座 会议送审 思路: 关键性会议SQL的编写后台实现前台实现 会议查询 MeetingInfoDao.java // 通用的会议查询SQL语句,包含会议信息表数据,主持人姓名、审批人姓名、会议状态private String getSQL() {return "…

四、MySQL(表操作)如何添加字段?修改表?删除字段?修改表名?删除表?格式化某张表?

1、添加字段 (1)基础语法: alter table 表名 add 字段名 类型名(长度) [comment注释] [约束]; (2)示例:添加nickname这个字段 2、修改表 修改表中某个字段的【数据类型】/【数据类型&字段名】 &…

【视频录制】MAC下录频软件对比

目录 各软件对比 OBS FiImage Omi录频专家 好录 各软件对比 名称下载地址优点缺点OBSOpen Broadcaster Software | OBS 1. 免费使用 2. 视频高清 3. 可做直播 1. 没有暂停继续 2. 开启没有缓冲时间,需要手动剪辑片头片尾 3. 配置音频麻烦 4. 有时会CPU很高卡死…

图像扭曲之锯齿

源码: void wave_sawtooth(cv::Mat& src,cv::Mat& dst,double amplitude,double wavelength) {dst.create(src.rows, src.cols, CV_8UC3);dst.setTo(0);double xAmplitude amplitude;double yAmplitude amplitude;int xWavelength wavelength;int yWave…

AES+base64+远程加载----ConsoleApplication811项目

ConsoleApplication9.cpp // ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include <Windows.h> #include <wininet.h> #include "base64.h" #include "AES.h" …

浅析三维模型OBJ格式轻量化压缩集群处理方法

浅析三维模型OBJ格式轻量化压缩集群处理方法 三维模型的OBJ格式轻量化压缩是指通过一系列技术和方法将三维模型的文件大小进一步减小&#xff0c;以提高模型在计算机中的加载、传输和存储效率。集群处理技术是指利用多台计算机构成的集群来并行处理任务&#xff0c;以加速计算过…

FPGA GTX全网最细讲解,aurora 8b/10b协议,HDMI板对板视频传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、GTX 全网最细解读GTX 基本结构GTX 发送和接收处理流程GTX 的参考时钟GTX 发送接口GTX 接收接口GTX IP核调用和使用 4、设计思路框架视频源选择IT6802解码芯片配置及采集动态彩条视频数据组包GTX aurora 8b/10b数据…

激活函数总结(二十三):激活函数补充(Piecewise Linear Unit、CLL)

激活函数总结&#xff08;二十三&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 Piecewise Linear Unit激活函数2.2 Complementary Log-Log (CLL)激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PReLU…

数学建模:BP神经网络模型及其优化

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 BP神经网络算法流程代码实现 神经网络的超参数优化代码实现 神经网络的分类 BP神经网络 算法流程 设 x 1 , x 2 , . . . , x i x_1,x_2,...,x_i x1​,x2​,...,xi​ 为输入变量&#xff0c; y y y…

图像分类学习笔记(六)——ResNeXt

一、要点 ResNeXt是ResNet的小幅升级&#xff0c;更新了block 左边&#xff08;ResNet的block/50/101/152层&#xff09;&#xff1a; 对于输入通道为256的特征矩阵&#xff0c;首先使用64个11的卷积核进行降维&#xff0c;再通过64个33的卷积核处理&#xff0c;再通过256个1…

volatile考点分析

今天我们学习并发编程中另一个重要的关键字volatile&#xff0c;虽然面试中它的占比低于synchronized&#xff0c;但依旧是不可忽略的内容。 关于volatile&#xff0c;我收集到了8个常见考点&#xff0c;围绕应用&#xff0c;特点和实现原理。 volatile有什么作用&#xff1f…