monitorenter:
每一个对象都会和一个监视器monitor关联。监视器被占用时会被锁住,其他线程无法获取该monitor。当JVM执行某个线程的某个方法内部的monitorenter时,它会尝试获取当前对象对应的monitor的所有权,其过程如下:
1,若monitor的进入数为0,线程可以进入monitor,并将monitor的进入数设置为1,当前线程成为monitor的owner(所有者)
2,若线程已拥有monitor的所有权,允许它重入monitor,则进入monitor的进入数加1
3,若其他线程已经占有monitor的所有权,那么当前尝试获取monitor的所有权的线程会被阻塞,直到monitor的进入数变为0,才能重新尝试获取monitor的所有权。
monitorentry小结:
synchronized的锁对象会关联一个monitor,这个monitor不是我们主动创建的,是JVM的线程执行到这个同步代码块,发现锁对象没有monitor就会创建monitor,monitor内部有两个重要的成员变量owner:拥有这把锁的线程,recursions会记录线程拥有锁的次数,当一个线程拥有monitor后其他线程只能等待。
monitorexit:
1,能执行monitorexit指令的线程一定是拥有当前对象的monitor所有权的线程
2,执行monitorexit时会将monitor的进入数减1,当monitor的进入数减为0时,当前线程退出monitor,不再拥有monitor的所有权,此时其他被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权
monitorexit释放锁
monitorexit插入在方法结束处和异常处,JVM保证每个monitorenter必须有对应的monitorexit。
同步方法(即方法头加了synchronized关键字的方法)会隐式调用monitorenter和monitorexit。在执行同步方式会调用monitorenter,在执行完同步方法后会调用monitorexit.
小结:
通过javap反汇编看到synchronized使用了monitorenter和monitorexit两个指令,每个锁对象都会关联一个monitor(监视器,他才是真正的锁对象),它内部有两个重要的成员变量owner(保存获取锁的线程),recursions(保存线程获得锁的次数),当执行到monitorexit时,recursions会减1,当计数器减到0时,这个线程就会释放锁