文章目录
Java 对象头
以 32 位虚拟机为例
普通对象
数组对象
其中 Mark Word 结构为
64 位虚拟机 Mark Word
参考资料
https://stackoverflow.com/questions/26357186/what-is-in-java-object-header
Monitor(锁)
Thread2开始执行,注意,obj是Java的对象, Monitor是操作系统提供的,靠指针关联
Thread2加锁后
假如再来一个Thread1,检查发现Obj已经关联了一个Monitor了,检查Montior的Owner,发现已经关联了Thread2(Owner只能关联一个),那Thread1就进入EntryList,开始Block状态。
如果有一个线程来了,Thread3,同样进入EntryList,开始blocked(EntryList底层是链表)
当Thread2执行完,空出了Owner
这时候Monitor去EntryList中唤醒一个(根据规则),假如唤醒thread1,就让Thread1关联Owner,进入运行态,thread3继续保持blocked
总结如下:
原理之 synchronized
不会造成加了锁解不了
原理之 synchronized 进阶
小故事
故事角色
- 老王 - JVM
- 小南 - 线程
- 小女 - 线程
- 房间 - 对象
- 房间门上 - 防盗锁 - Monitor
- 房间门上 - 小南书包 - 轻量级锁
- 房间门上 - 刻上小南大名 - 偏向锁
- 批量重刻名 - 一个类的偏向锁撤销到达 20 阈值
- 不能刻名字 - 批量撤销该类对象的偏向锁,设置该类不可偏向
小南要使用房间保证计算不被其它人干扰(原子性),最初,他用的是防盗锁,当上下文切换时,锁住门。这样,即使他离开了,别人也进不了门,他的工作就是安全的。
但是,很多情况下没人跟他来竞争房间的使用权。小女是要用房间,但使用的时间上是错开的,小南白天用,小女晚上用。每次上锁太麻烦了,有没有更简单的办法呢?.
小南和小女商量了一下,约定不锁门了,而是谁用房间,谁把自己的书包挂在门口,但他们的书包样式都一样,因此每次进门前得翻翻书包,看课本是谁的,如果是自己的,那么就可以进门,这样省的上锁解锁了。万一书包不是自己的,那么就在门外等,并通知对方下次用锁门的方式。
后来,小女回老家了,很长一段时间都不会用这个房间。小南每次还是挂书包,翻书包,虽然比锁门省事了,但仍然觉得麻烦。
于是,小南干脆在门上刻上了自己的名字:【小南专属房间,其它人勿用】,下次来用房间时,只要名字还在,那么说明没人打扰,还是可以安全地使用房间。如果这期间有其它人要用这个房间,那么由使用者将小南刻的名字擦掉,升级为挂书包的方式。
同学们都放假回老家了,小南就膨胀了,在 20 个房间刻上了自己的名字,想进哪个进哪个。后来他自己放假回老家了,这时小女回来了(她也要用这些房间),结果就是得一个个地擦掉小南刻的名字,升级为挂书包的方式。老王觉得这成本有点高,提出了一种批量重刻名的方法,他让小女不用挂书包了,可以直接在门上刻上自己的名字。
后来,刻名的现象越来越频繁,老王受不了了:算了,这些房间都不能刻名了,只能挂书包。
轻量级锁
锁膨胀
自旋优化
偏向锁
偏向状态
撤销-调用对象hashCode
撤销——其他线程适用对象
撤销——调用wait/notify
因为wait/notify只有重量级锁有,所以,调用的时候就要升级为重量级锁。
批量重偏向
批量撤销
锁消除
JIT即时编译器会优化热点代码(就是重复执行的),发现o变量不会被共享,JIT就把synchronized操作优化掉了。
可以加上参数,就可以关闭JIT优化。