重量级锁(monitor)
每一个对象都有对象头 对象头中有markWord
markWord中存储了该对象的hashCode,分代年龄,加锁状态 等信息
对某一个对象加锁,其实就是java使用系统的monitor(监视器/管程) 与该对象进行关联
monitor会先把该对象中markWord的各种信息存储起来 ,
然后把该对象markWord中的信息置为该monitor的指针
使用synchronized (对象) 就是把该对象与monitor进行关联
当多个线程1,2,3同时执行到synchronized(对象){}时,
(假设线程1先执行)->线程1会拿到对象,
然后将对象中的markWord信息置为monitor指针 ,
然后把monitor中的owner(主人)属性设置为线程1,表示该对象的锁已经被线程1持有了
线程2或者线程3也执行到该 synchronized(对象){}时 ,
会通过对象中的monitor指针找到该monitor,但是此时monitor中的 owner是线程1,锁已经被线程1占据了
所以线程2和线程3会直接进入monitor中的entryList进行等待
当线程1执行完代码(无论同步代码块是否有异常,都会释放锁),monitor会将owner设置为空(锁被释放了),然后把对象的markWord重置回来,
然后唤醒线程2和线程3,两个线程开始争抢时间片的使用权,
成功的那个线程会再次重复线程1之前的步骤,直至所有线程都执行完毕
轻量级锁
轻量级锁 : 第一次加锁 线程会创建一个锁记录,
把被锁对象头中的 markword 数据存入锁记录中,
并把object reference指向该对象,
此时该对象的锁状态也会被改为轻量级锁状态00
锁重入
锁重入 : 同一个线程 对同一个对象多次加锁
同一个线程对同一个对象再次加锁,线程还会创建一个锁记录,
但由于第一次对象头已经被改为了已锁状态,
markword也被放入了第一个锁记录中,
所以第二次加锁,锁记录中只会存储指向对象的地址,而不会存储该对象的markword信息,
那么第二次的锁记录还有什么用呢?该记录可以当做解锁的计数器使用,
在代码执行完后,告诉程序加了几次锁,那么程序就会解几次锁
锁膨胀
锁膨胀 : 轻量级锁变成重量级锁的过程
第一个线程对一个对象加轻量级锁后 第二个线程再次来加锁(加锁失败),
此时由于该对象已经有了轻量级锁,会发生锁膨胀
即为该对象申请一个monitor锁(重量级锁),
并把该对象markword中的地址指向monitor,
第二个线程会进入monitor的entryList等待,
当第一个线程执行完毕后,进入解锁流程(轻量级锁解锁失败),
但由于此时对象中的markword已经存储的是重量级锁中的地址,
所以会进入重量级解锁流程,通过markword中的monitor地址找到monitor,
把monitor中的owner设置为空,唤醒entryList中阻塞的第二个线程