当前位置:网站首页>Synchronized和volatile 面试简单汇总
Synchronized和volatile 面试简单汇总
2022-07-31 14:50:00 【高个子男孩】
synchronized
Synchronized的作用主要有三个:
确保线程互斥的访问同步代码
保证共享变量的修改能够及时可见
有效解决重排序问题
从语法上讲,Synchronized总共有三种用法:
修饰普通方法
修饰静态方法
修饰代码块
synchronized修饰普通方法时,使用的锁是对象的锁。
synchronized修饰静态方法时,使用的锁是类对象的锁Class。
synchronized修饰的代码块 使用的锁是对象锁。
监视者monitorenter
当对象被占用时就会变成锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
如果monitor的进入数字为0,则该线程进入monitor,然后将进入数字设置为1,该线程即为monitor的所有者。
如果线程已经占有该monitor,只是重新进入,则进入显示器的进入数加1。
如果其他线程已经占用了monitor,则该线程进入双向状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
监控退出monitorexit
执行monitorexit的线程必须是objectref所对应的monitor的所有者。
指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被该monitor的线程可以尝试去获取这个monitor的所有权。
通过这两段描述,我们应该能很清楚的修剪Synchronized的实现原理,Synchronized的语义一致是通过一个monitor的对象来完成,实际上等待/通知等方法也依赖于monitor对象,这就是为什么只有在同步的块或方法中才能调用wait / notify等方法,否则会引发java.lang.IllegalMonitorStateException的异常的原因。
Synchronized底层实现方式
同步代码块


synchronized映射成字节码指令就是增加来两个指令:monitorenter和monitorexit。当一条线程进行执行的遇到monitorenter指令的时候,它会去尝试获得锁,如果获得锁那么锁计数+1(为什么会加一呢,因为它是一个可重入锁,所以需要用这个锁计数判断锁的情况),如果没有获得锁,那么阻塞。当它遇到monitorexit的时候,锁计数器-1,当计数器为0,那么就释放锁。
图上有2个monitorexit,synchronized锁释放有两种机制,一种就是执行完释放;另外一种就是发送异常,虚拟机释放。图中第二个monitorexit就是发生异常时执行的流程,就是“会有2个流程存在“。而且,从图中我们也可以看到在第13行,有一个goto指令,也就是说如果正常运行结束会跳转到19行执行。
同步方法


方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。
JVM就是根据该标示符来实现方法的同步的当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。
在方法执行期间,其他任何线程都无法再获得同一个monitor对象。其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。
synchronized与Lock的区别
类别 | synchronized | Lock |
存在层次 | Java的关键字,在jvm层面上 | 是一个类 |
锁的释放 | 1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 | 在finally中必须释放锁,不然容易造成线程死锁 |
锁的获取 | 假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待 | 分情况而定,Lock有多个锁获取的方式,大致就是可以尝试获得锁,线程可以不用一直等待 |
锁状态 | 无法判断 | 可以判断 |
锁类型 | 可重入 不可中断 非公平 | 可重入 可判断 可公平(两者皆可) |
性能 | 少量同步 | 大量同步 |
wait()与sleep()的区别,简单来说wait()会释放对象锁而sleep()不会释放对象锁。
volatile
内存可见性
Java 内存模型(JMM):在 Java 中所有的共享变量都在主内存中,每个线程都有自己的工作内存,为了提高线程的运行速度,每个线程的工作内存都会把主内存中的共享变量拷贝一份进行缓存,以此来提高运行效率。但这样就会产生一个新的问题,如果某个线程修改了共享变量的值,其他线程不知道此值被修改了,就会发生两个线程值不一致的情况,
内存的可见性是指线程修改了变量的值之后,其他线程能立即知道此值发生了改变。
volatile 只是轻量级的线程可见方式,并不是轻量级的同步方式,所以并不能说 volatile 是轻量级的 synchronized
内存屏障的3个功能:
I. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
II. 它会强制将对缓存的修改操作立即写入主存;
III. 如果是写操作,它会导致其他CPU中对应的缓存行无效。
边栏推荐
- 安装Xshell并使用其进行Ymodem协议的串口传输
- R语言ggplot2可视化:使用ggpubr包的ggboxplot函数可视化箱图、使用font函数自定义图例标题文本(legend.title)字体的大小、颜色、样式(粗体、斜体)
- c语言hello world代码(代码编程入门)
- Groupid(artifact id)
- 我把问烂了的MySQL面试题总结了一下
- C language basic practice (nine-nine multiplication table) and printing different asterisk patterns
- Five dimensions to start MySQL optimization
- 基于最小二乘法和SVM从天气预报中预测太阳能发电量(Matlab代码实现)
- MySql总结
- 【Pytorch】F.softmax()方法说明
猜你喜欢

梅克尔工作室-第一次

华医网冲刺港股:5个月亏2976万 红杉与姚文彬是股东

The recently popular domestic interface artifact Apipost experience

Redis 】 【 publish and subscribe message

OpenShift 4 - Deploy Redis Cluster with Operator

"Listen to me, thank you" can be said in ancient poetry?Tsinghua University has developed an artifact of "Searching Sentences According to Meaning", which can search for the famous sayings you want wi

Small test knife: Go reflection helped me convert Excel to Struct

消息队列消息数据存储MySQL表设计

Asynchronous processing business using CompletableFuture

格林美瑞交所IPO:募资3.8亿美元 更多中国企业将赴欧洲上市
随机推荐
使用 PyTorch 检测眼部疾病
Redis 】 【 publish and subscribe message
Sentinel热点参数限流
Nuget打包并上传教程
element-plus虚拟表格virtual-list组件中是怎么实现清理lodash.memoize缓存的?
OAuth2:四种授权方式
49. The copy constructor and overloaded 】
《微信小程序-进阶篇》Lin-ui组件库源码分析-Icon组件
【Pytorch】torch.argmax()用法
MySQL 23 classic interviews hang the interviewer
QGIS 加载WMS数据,重新投影
svn安装及使用(身体功能手册)
[QNX Hypervisor 2.2用户手册]9.13 rom
[QNX Hypervisor 2.2 User Manual] 9.13 rom
搭建私有的的Nuget包服务器教程
蔚来杯2022牛客暑期多校训练营4
NC | 中国农大草业学院杨高文组揭示发现多因子干扰会降低土壤微生物多样性的积极效应...
力扣:738.单调递增的数字
ML、DL、CV常见的问题整理
Nuget打包并上传教程