当前位置:网站首页>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中对应的缓存行无效。
边栏推荐
- sentinel与nacos持久化
- abaqus find contact pairs报错:surface name is already in use
- OpenShift 4 - 用 Operator 部署 Redis 集群
- svn安装及使用(身体功能手册)
- 高等数学——常用不定积分公式
- 名创优品斥资6.95亿购买创始人叶国富所持办公楼股权
- [Pytorch] F.softmax() method description
- MANIFEST.MF文件(PDB文件)
- The 232-layer 3D flash memory chip is here: the single-chip capacity is 2TB, and the transmission speed is increased by 50%
- Trigonometric identity transformation formula
猜你喜欢

Sentinel热点参数限流

MySQL【子查询】

深入浅出边缘云 | 4. 生命周期管理

UnityShader入门学习(二)——渲染流水线

分成两栏后文字顺序混乱的问题解决【写期刊论文时】

Getting started with UnityShader (3) - Unity's Shader

In the future, the interviewer asks you why it is not recommended to use Select *, please answer him out loud!

LeetCode二叉树系列——226.翻转二叉树

Sentinel服务熔断和降级

Prometheus之node_exporter性能监控信息采集含义
随机推荐
NPM Taobao mirror (latest version) released a new version of npm mirror at 2021-11-21 16:53:52 [easy to understand]
OAuth2:使用JWT令牌
OpenCV测量物体的尺寸技能 get~
I summed up the bad MySQL interview questions
The recently popular domestic interface artifact Apipost experience
How to grab configuration information for DELL SC compellent storage system
Node实现数据加密
LeetCode二叉树系列——226.翻转二叉树
OAuth2:微服务权限校验Session共享
谷歌CTS测试(cta测试)
redhat/openssl generates a self-signed ca certificate and uses it
Sentinel服务熔断和降级
R语言检验样本是否符合正态性(检验样本是否来自一个正态分布总体):shapiro.test函数检验样本是否符合正态分布(normality test)
基于极限学习机(ELM)进行多变量用电量预测(Matlab代码实现)
消息队列消息数据存储MySQL表设计
模板与泛型编程值typelist实现
Analysis of the startup source code of hyperf (2) - how the request reaches the controller
华医网冲刺港股:5个月亏2976万 红杉与姚文彬是股东
分成两栏后文字顺序混乱的问题解决【写期刊论文时】
Open Inventor 10.12 Major Improvements - Harmony Edition