一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
Java对象头
以32位虚拟机为例
普通对象
Klass Word 指向所属的Class类对象
数组对象
其中MarkWord的结构为
64位虚拟机mark word
Moniter工作原理
Monitor 被翻译为监视器或管程
每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的Mark Word 中就被设置指向 Monitor 对象的指针
Monitor 结构如下
-
刚开始 Monitor 中 Owner 为 null
-
当 Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor中只能有一个 Owner
-
在 Thread-2 上锁的过程中,如果 Thread-3,Thread-4,Thread-5 也来执行 synchronized(obj),就会进入EntryList BLOCKED
-
Thread-2 执行完同步代码块的内容,然后唤醒 EntryList 中等待的线程来竞争锁,竞争的时是非公平的
-
图中 WaitSet 中的 Thread-0,Thread-1 是之前获得过锁,但条件不满足进入 WAITING 状态的线程,后面讲wait-notify 时会分析
注意:
synchronized 必须是进入同一个对象的 monitor 才有上述的效果
不加 synchronized 的对象不会关联监视器,不遵从以上规则
注意: 方法级别的synchronized不会在字节码指令中有所体现
synchronized优化
小故事
故事角色
老王 - JVM
小南 - 线程
小女 - 线程
房间 - 对象
房间门上 - 防盗锁 - Monitor
房间门上 - 小南书包 - 轻量级锁
房间门上 - 刻上小南大名 - 偏向锁
批量重刻名 - 一个类的偏向锁撤销到达 20 阈值
不能刻名字 - 批量撤销该类对象的偏向锁,设置该类不可偏向
小南要使用房间保证计算不被其它人干扰(原子性),最初,他用的是防盗锁,当上下文切换时,锁住门。这样,
即使他离开了,别人也进不了门,他的工作就是安全的。
但是,很多情况下没人跟他来竞争房间的使用权。小女是要用房间,但使用的时间上是错开的,小南白天用,小女
晚上用。每次上锁太麻烦了,有没有更简单的办法呢?
小南和小女商量了一下,约定不锁门了,而是谁用房间,谁把自己的书包挂在门口,但他们的书包样式都一样,因
此每次进门前得翻翻书包,看课本是谁的,如果是自己的,那么就可以进门,这样省的上锁解锁了。万一书包不是
自己的,那么就在门外等,并通知对方下次用锁门的方式。
后来,小女回老家了,很长一段时间都不会用这个房间。小南每次还是挂书包,翻书包,虽然比锁门省事了,但仍
然觉得麻烦。
于是,小南干脆在门上刻上了自己的名字:【小南专属房间,其它人勿用】,下次来用房间时,只要名字还在,那
么说明没人打扰,还是可以安全地使用房间。如果这期间有其它人要用这个房间,那么由使用者将小南刻的名字擦
掉,升级为挂书包的方式。
同学们都放假回老家了,小南就膨胀了,在 20 个房间刻上了自己的名字,想进哪个进哪个。后来他自己放假回老
家了,这时小女回来了(她也要用这些房间),结果就是得一个个地擦掉小南刻的名字,升级为挂书包的方式。老
王觉得这成本有点高,提出了一种批量重刻名的方法,他让小女不用挂书包了,可以直接在门上刻上自己的名字
后来,刻名的现象越来越频繁,老王受不了了:算了,这些房间都不能刻名了,只能挂书包