闲来整理下, 都是自己理解的东西, 可能不是全然正确, 和大家一起探讨.
了解sychronize锁定了什么
了解这三种锁, 先要从synchronize关键字说起.sychronize其实最终锁定的是对象. 不过 synchronize 加在 方法上, 代码块上, 静态代码块上. 加在这三个地方, 锁定的对象是不一样的.
synchronize修饰 | 锁定对象 |
---|---|
方法 | 锁定的是调用者对象 |
代码块 | synchronize(被锁定对象){} |
静态代码块 | 当前class对象 |
了解对象的 Mark word(对象头)
当线程调用到synchronize 修饰的代码时, 会去修改被锁定对象的 Mark word (对象头)中一些属性, 我们看下对象头有哪些属性.
可以看到在对象头中, 关于无锁, 偏向, 轻量, 重量锁的属性是不一样的.
实际出现锁的时机与锁升级
我们现在假设三种情况:
-
只有T1 线程调用sychronize 代码 (出现偏向锁):
step1 : 首先通过 被锁定对象 的对象头属性, 判断是否是偏向锁.
case1 如果是偏向锁 : 比较ThreadId是否相同,相同则执行.
case2 如果不是偏向锁 : , 通过cas 修改ThreadId, 将线程的threadId 设置进去.
这个时候只有偏向锁. 每次T1 线程调用的时候, 只需要判断是否偏向锁, 对比ThreadId 就可以了. -
T1, T2 两个线程调用sychronize 代码( 出现偏向锁 升级为轻量锁)
假设T1 获取到执行权, T2 线程与T1 线程出现竞争. 将轻量锁属性设置1. T2 线程没有获取到执行权, 就开始自旋等待(自旋一定次数,jvm参数可配置) . 自旋的开销, 比映射到内核切换线程的开销要低. -
T1, T2 两个线程调用sychronize 代码(出现 轻量锁 升级为重量锁)
第二种情况, 提到了自旋一定次数. 那么如果超过指定次数. 轻量锁就会升级成为重量锁. 重量锁就是利用Monitor 指针. 通过系统来分配切换代码的执行权.总结:
这些是自己总结的一些内容. 欢迎指正探讨.