【面试题】说说synchronized关键字的底层原理是什么?
synchronized:内存屏障、CPU硬件级别的原理,原子性、可见性、有序性、指令重排、偏向锁等等
用法: 可以对对象加锁,也可以对类加锁
synchronized(myObject){
//一堆代码
synchronized(myObject){
//一堆代码
}
}
synchronized(otherObject.class){
//一堆代码
}
synchronized该关键字在编译成class文件后可以看到对应的语句是monitorEnter与monitorExit
synchronized底层原理,跟JVM指令和monitor有关。如果用到了synchronized关键字,在底层编译后的JVM指令中,会有monitorenter和monitorexit两个指令
monitorenter指令执行:
每个对象都有一个关联的monitor,一个对象实例就有一个monitor,一个类的class对象也有一个monitor。如果要对这个对象加锁,那么必须获取这个对象关联的monitor的lock锁
原理:
monitor中有个计数器,默认为0。如果一个线程要获取monitor的锁,会去判断当前计数器是否为0,如果为0,那么可以获得锁,然后对计数器加1。
对象锁重入
如果一个线程第一次synchronized,获取到了myObject对象的monitor的锁,计数器+1,第二次synchronized,会再次获取myObject对象的monitor的锁,这个就是重入加锁,然后计数器+1,变成2
如果有其他的线程进入synchronized,会发现myObject对象的monitor锁的计数器不等于0,意味着被别的线程加锁了,那么这个线程就会进入block阻塞状态,等待其他线程释放锁后去获取锁。
如果出了synchronized修饰的代码片段范围,在底层会有一个monitorexit的指令。此时获取锁的线程会对对象的monitor计数器-1,如果有多次重入加锁就会多次-1,直到计数器为0
后面block阻塞的线程,会再次尝试获取锁。(最终只有一个线程能获取到锁)
锁互斥
线程1 上锁 monitor=1
线程2 发现monitor=1 阻塞等待 加锁失败
线程1 释放锁 monitor=0
线程2 发现monitor=0 加锁成功 monitor=1
以上为synchronized略微略微底层原理
【评论区】
1.synchronized底层原理
(1)依赖底层JVM的指令,线程执行被synchronized修饰的方法时,通过ACC_SYNCHORNIZED关键字,判断方法是否同步
(2)执行被修饰的代码块时先执行monitorEnter指令
(3)monitor中有一个计数器,初始为0
(4)尝试获取monitor的锁,会先判断计数器的值是否为0
(a)如果为0,则上锁,对monitor的计数器+1(可以锁重入)
(b)如果不为0,且当前线程不是自己,进入block阻塞状态等待
(5)执行完代码退出方法后会执行monitorExit指令,monitor的计数器-1(锁重入时,多次-1,直到为0)
(6)其他处于block阻塞状态的线程尝试获取锁(非公平锁)
代码块同步是使用 monitorenter 和 monitorexit 指令实现的
方法同步通过调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的
上一篇: 【面试】web前端经典面试题试题及答案-jQuery
下一篇: Python——列表,元组