- Klass
- Monitor
- 对象头
- 锁优化
- jstack
- javap
特性
- 三大特性:可见性、原子性、有序性
- 可重入性
- 不建议用String、final类作为锁
原理
- 同步方法是基于ACC_SYNCHRONIZED标识符
- 同步块是基于moniterenter和monitorexit
二者都试图获取对象的monitor。
JSE1.6以前的synchronized
以前是基于重量级锁的。每次moniterenter,都试图获取monitor,获取失败就会阻塞休眠,当并发量较小的时候,带来的延迟比较大。
举个形象的例子:
每次你想去拿锁,拿到就继续做事,拿不到就睡一觉,等别人把锁还回去。结果一觉醒来天都黑了,人家早就把锁还回去了。
JSE1.6以后的synchronized
除了重量级锁外,还引入了偏向锁、轻量级锁。三者的具体行为我就不说了,网上的流程图已经够了,这里记录自己的理解。
- 偏向锁。相当于女朋友(偏向锁)只能独属于一个人(线程)。
如果另一个人来,发现名花有主,就推翻重来,"我和她谈不了你也别谈了"。
这时,如果她男朋友正和女友亲嘴(线程没有休眠),就等她们亲完嘴再让他们分手(等到全局安全点再暂停线程)。如果不是(线程已经休眠),就直接当他们分手了。
之后谁再想和她谈女朋友,就得用原地等待(轻量级锁)的方式竞争。 - 轻量级锁。当你试图和女生谈朋友时,如果人家名花有主,就原地等着,像个sb一样等着,等到人家分手了 ,你就能和她谈了。好处是如果别人没多久就分手了,你就赚了,如果别人一直谈着,那你就像个sb一样等着吧。
如果等了太久都没分手,竞争条件就改为睡一觉再追妹子(重量级锁)。现任男朋友分手了以后(释放锁以后),要是再想和女朋友谈恋爱(想再度获取锁),也得按重量级锁的方式来。 - 重量级锁。了解下monitor对象的工作原理即可。简单讲就是"追不到就落选到entry_list里,然后睡一觉,等到下次被叫醒了再去竞争" 建议参考java锁池与等待池
object.notifyAll唤醒的全部线程是如何竞争的 ?会不会再次阻塞?又是如何排队的?
monitor底层基于操作系统的mutexLock,所以object.notifyAll唤醒的线程就 取决于mutexLock了吧。
(需要验证)