欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【面试题】说说synchronized关键字的底层原理是什么?

程序员文章站 2022-04-19 15:33:38
...

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 标志来隐式实现的

 

相关标签: 线程