一丶Monitor
1、什么是Monitor?
被翻译为监视器或者管程。
每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark World就被设置指向Monitor对象的指针。
Monitor结构如下:
- 线程2访问同步代码块synchronized(obj)
- obj的Mark World指向Monitor,Monitor的owner指向线程2
- 线程345来synchronized(obj)的时候,发现owner有人了,就进入blocked状态,等待
- 线程2执行完,owner为空,通知EntryList内的线程去竞争(非公平:先进来的不见得先执行)
- 竞争到的线程再变成为owner
- 线程01是获得过锁不满足执条件的线程
注意:同一个对象才会关联到同一个Monitor
2、源码解析
等有时间写一下源码分析
二、锁
1、重量级锁
重量级锁就是Monitor
2、轻量级锁
1.创建锁记录对象(Lock Record),每个线程的栈帧都会包含一个锁记录结构,内部可以存储锁定对象的Mark World
2.让锁记录中的Object reference指向锁对象,并尝试用cas替换Object的Mark Word,将Mark Word的值存在锁记录(红色箭头代表交换;01表示无锁;00表示轻量级锁)
3.如果CAS替换成功,对象头存放了锁记录地址和状态00,表示该线程给对象加锁
4.如果CAS失败有两种情况
- 如果其他线程已经持有该obj的轻量级锁,就会锁膨胀
- 如果时自己执行synchronized锁重入,那么再添加一条Lock Record作为重入的计数
5.退出synchronized的时候如果有null表示有锁重入,清除之后计数-1
6.退出synchronized,当锁记录值不为null,这时使用CAS把markword的值恢复给对象头
- 成功:解锁
- 失败:说明锁成了重量级锁,进入重量级锁解锁流程
3、锁膨胀
如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其他线程为此对象加上轻量级锁(有竞争),这时需要进行锁膨胀,把轻量级锁变为重量级锁
- 当线程1进行轻量级加锁时,线程0已经对该对象加了轻量级锁
- 这时线程1加轻量级锁失败,进入锁膨胀流程
- 即为Object对象申请Monitor锁,让Object指向重量级锁地址(重量级锁10)
- 然后自己进入Monitor的EntryList BLOCKED
|
- 线程0解锁,使用CAS将Mark Word的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照Monitor地址找到Monitor对象,设置Owner为null,唤醒EntryList中Blocked的线程
4、自旋优化
5、偏向锁
5.1、定义
5.2、偏向锁撤销
1、调用对象的hashCode()
2、线程1加锁,释放,然后线程2加锁发现已经属于线程1,会给线程加一个轻量级锁,用完后释放
3、调用wait/notify
4、批量重新偏向:线程1执行很多次一直加锁解锁,都是偏向锁,线程2加轻量级锁,解锁之后都是轻量级锁,当到达一个阈值(20)之后,可以重新偏向给线程2
5、批量撤销
5.3、锁消除
对象根本不会被其他线程操作的时候,jit会进行优化,把锁去掉,可以加参数取消掉锁消除