synchronized关键字底层原理

synchronized底层的原理,跟jvm指令和monitor有关系

如果用到了synchronized关键字,在底层编译后的jvm指令中,会有monitorenter和monitorexit两个指令

monitorenter

// 代码对应的指令

monitorexit

synchronized关键字底层原理_第1张图片

每个对象都会关联一个monitor,比如一个对象实例就有一个monitor,一个类的Class对象也有一个monitor,如果要对这个对象加锁,那么必须获取这个对象关联的monitor的lock锁

 

synchronized关键字底层原理_第2张图片

monitor里会有一个计数器,从0开始,如果一个线程想要获取monitor锁,看它的计数器是否为0,如果为0,那么说明锁空闲,它就可以获取锁了,然后计数器加1

另外monitor的锁是支持重入加锁的

 

synchronized(myLock){ (1)

       // 代码

       synchronized(myLock){ (2)

           //代码

       }

}

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

synchronized关键字底层原理_第3张图片

 

这个时候如果其它线程,第一次执行到synchronized那里,会发现myLock对象的monitor锁的计数器是大于0的,意味着被别的线程加锁了,然后此时线程会进入block阻塞状态,等待获取锁。

synchronized关键字底层原理_第4张图片

 

解锁流程

synchronized(myLock){ (1)

       // 代码

       synchronized(myLock){ (2)

           //代码

       } // 解锁 计数器减1

} // 解锁 计数器减1

synchronized关键字可以同时保证原子性,可见性和有序性

原子性:原子性层面而言,有一个加锁和释放锁的机制,加锁之后,同一段代码只有自己可以执行,通过ObjectMonitor

可见性:可见性会通过加入一些内存屏障,在同步代码块对变量做的写操作,都会在释放锁的时候,全部执行flush操作,在进入同步代码块的时候,对变量的读操作,全部会强制执行refresh操作

有序性:有序性会通过各种各样的内存屏障,来解决LoadLoad,StoreStore,StoreLoad,LoadStore等等重排序,通过Acquire屏障和Release屏障,保证同步代码块内部的指令和外部的指令不能重排,Acquire就是LoadLoad和LoadStore屏障,Release就是StoreLoad和StoreStore屏障

 

synchronized关键字底层原理_第5张图片

你可能感兴趣的:(java)