Synchronized原理分析

并发的三大特性

        并发三大特性:原子性、可见性、有序性。之前我们说过volatile,它可以保证可见性和有序性,但是不能保证原子性。具体详见 https://blog.csdn.net/u010096526/article/details/133817363,这次说的Synchronized确是能保证这3种特性的。

原子性

        我们都知道原子性的定义是:要么都执行,要么都不执行。类似i++和i+=1这种,都不是原子性的。因为它拆分了数据的读取、计算、赋值。而synchronized修饰的类或对象的操作都是原子性的,因为只要获取到锁,直到锁释放,这中间的过程无法被打断。所以保证了原子性。

可见性

        volatile的可见性是通过locks前缀指令和内存屏障来保证的。synchronized修饰类或对象时,一个线程如果想访问这个该类或对象,必须要先获取锁,而这个锁的状态对其他线程都是可见的,并且会在锁释放之前会将对变量的修改刷回主存,这就是保证了可见性。

有序性

        会保证代码的执行顺序,防止指令重排。volatile是通过内存屏障。而synchronize本来就是控制只能单线程访问,所以单线程肯定是有序的。

原理     

   Synchronized原理分析_第1张图片        

        其实synchronized底层的原理,是跟jvm指令和monitor有关系的。在底层编译后的jvm指令中,会有monitorenter和monitorexit两个指令。

        每个对象都有一个关联的monitor,比如一个对象实例就有一个monitor,一个类的Class对象也有一个monitor,如果要对这个对象加锁,那么必须获取这个对象关联的monitor的lock锁。monitor里面有一个计数器,从0开始的。如果一个线程要获取monitor的锁,就看看他的计数器是不是0,如果是0的话,那么说明没人获取锁,他就可以获取锁了,然后对计数器加1。

        Synchronized可重入锁也是根据monitor的计数器。

        如果一个线程第一次synchronized那里,获取到了myObject对象的monitor的锁,计数器加1,然后第二次synchronized那里,会再次获取myObject对象的monitor的锁,这个就是重入加锁了,然后计数器会再次加1,变成2。

        这个时候,其他的线程在第一次synchronized那里,会发现说myObject对象的monitor锁的计数器是大于0的,意味着被别人加锁了,然后此时线程就会进入block阻塞状态,什么都干不了,就是等着获取锁。

        接着如果出了synchronized修饰的代码片段的范围,就会有一个monitorexit的指令,在底层。此时获取锁的线程就会对那个对象的monitor的计数器减1,如果有多次重入加锁就会对应多次减1,直到最后,计数器是0。

        然后后面block住阻塞的线程,会再次尝试获取锁,但是只有一个线程可以获取到锁。

你可能感兴趣的:(Java并发编程系列,java)