提示
年轻人不讲理论
锁升级
无锁 → 偏向锁 → 轻量级锁 → 重量级锁
伪代码
//伪代码
class A{
synchronize hello(){
hi();
}
synchronize hi(){
sout("hi")
}
main(){
A a = new A();
new Thread( a.hello(), "1线程").start;
new Thread( a.hello(), "2线程").start;
new Thread( a.hello(), "3线程").start;
new Thread( a.hello(), "4线程").start;
}
}
锁升级过程
最复杂情况下:
-
1线程调用a对象hello方法,需要锁住a对象,查看a对象头存储的锁标志为无锁(lock : 01,biased_lock : 0),线程重入次数recursions=0,将锁标志改为偏向锁(lock : 01,biased_lock : 1),a对象头中设置正在运行的线程id为1线程的id,线程重入次数recursions++
-
1线程调用hi方法,需要锁住a对象,查看对象头锁标志为偏向锁,拥有锁的线程id和自己线程id一致,不需要抢夺锁,只需要将线程重入次数recursions++(可重入)
-
1线程调用未结束
-
2线程调用a对象hello方法,需要锁住a对象,查看a对象头存储的锁标志为偏向锁,将锁标志改为轻量级锁(lock : 00),2线程做CAS自旋,循环获取锁
-
3线程调用a对象hello方法,需要锁住a对象,查看a对象头存储的锁标志为轻量级锁,3线程直接做CAS自旋,循环获取锁
-
2,3线程循环时间达到阈值,或者多个线程都在此自旋(自旋浪费cpu),将a对象头中的锁标志改为重量级锁(lock : 10)
-
2,3线程查看a对象头锁标志为重量级锁,直接将线程放入a对象头中的线程等待队列,不再自旋
-
4线程调用a对象hello方法,需要锁住a对象,查看a对象头存储的锁标志为重量级锁,直接进入等待队列
-
1线程调用hi结束,线程重入次数recursions - -
-
1线程调用hello结束,线程重入次数recursions - -
-
1线程释放锁并唤醒其它等待线程(非公平锁)
-
等待线程并不是按排队顺序获取锁,而是一起抢夺锁(非公平锁)