☕【JVM技术探索】深入分析各种锁(锁膨胀)运作流程

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前提承接","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"针对于之前两篇关于synchronized的文章,主要介绍关于synchronized在字节码中的实现方式和表现形式(同步代码块和同步方法)","attrs":{}},{"type":"link","attrs":{"href":"https://my.oschina.net/liboware/blog/5054980","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Java并发编程专题系列之深入分析synchronized(基础篇)","attrs":{}}]},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"以及先关针对于同步锁的实现原理比如ObjectMonitor的数据结构以及等待队列和同步队列等","attrs":{}},{"type":"link","attrs":{"href":"https://my.oschina.net/liboware/blog/5059359","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Java并发编程专题系列之深入分析synchronized(进阶篇)","attrs":{}}]},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":",本文主要介绍针对于在执行角度包含对象锁的结构(标记字段的状态)和相关加锁过程进行相关的流程梳理以及对前两章的总结","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"synchronized关键字","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"synchronized的锁机制的主要优势是Java语言内置的锁机制,因此,JVM可以自由的优化而不影响已存在的代码","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"任何对象都拥有对象头这一数据结构来支持锁,但是对于较大的对象系统开销会更大一些。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"java","attrs":{}},{"type":"text","text":"中的每一个对象都至少包含2个字(","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"2 * 4 Bytes for 32bits & 2 * 8 Bytes for 64bits, 不包括已压缩的对象","attrs":{}},{"type":"text","text":")。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第一个字被称为Mark Word。这是一个对象的头,它包含了不同的信息,包括锁的相关信息","attrs":{}},{"type":"text","text":"(32bitOS->8bit大小、64bitOS->16bit大小)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第二个字是指向metadata class的指针,metadata class字义了对象的类型。这部分也包含了VMT(Virtual Method Table)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Mark Word 的结构如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/14/140a62469f5ab8397a6568eba9bdde11.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Mark Word根据最低两位(Tag)的所表示的对象状态(包含了锁的类型),编码了不同的信息","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果这个对象没有被用作锁,Mark Word 记录了hashcode和对象年龄(for GC/survivors)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除此之外,有3种状态对应锁:轻量级锁,重量级锁和偏向锁。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"轻量级锁","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"现代JVM都引入了轻量级锁","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"避免将每个对象关联操作系统的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mutex/condition","attrs":{}},{"type":"text","text":"变量(","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"重量级锁","attrs":{}},{"type":"text","text":")","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"当不存在锁竞争时,使用原子操作来进入退出同步块","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果发生锁竞争,回退到操作系统的重量级锁","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"引入轻量级锁会提供锁效率,因为大部分锁都不存在竞争","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"轻量级锁的加锁过程","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"当一个对象被锁定时,mark word被复制到当前尝试获取锁的线程的线程栈(Execution stack)的锁记录空间(lock record), 被复制的mark word官方称为displaced mark","attrs":{}},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用CAS操作来尝试使","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mark word","attrs":{}},{"type":"text","text":"指向当前线程的锁记录空间(即在mark word中存入使用","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"当前线程锁记录空间的指针——stack pointer","attrs":{}},{"type":"text","text":")。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS操作成功,则线程获得锁","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS操作失败,即存在锁竞争,则发生锁膨胀,回退到重量级锁","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"锁记录空间中记录了被当前执行方法锁定的对象(通过遍历线程栈找到线程的锁对象)。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"轻量级锁加锁前:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/36/36ae9887c061edd4025752f2434ebeaa.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"轻量级锁加锁后:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e8/e8b9c4011a426d5dd482b5b7dbe8f61a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"经量级锁的解锁过程:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"解锁使用CAS来把","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"displaced mark","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"写回对象的mark word中","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果CAS失败, 表示发生锁竞争:则锁膨胀。(通知其他等待线程锁已释放)将锁记录空间置为0","attrs":{}},{"type":"text","text":";","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果发生锁膨胀,则用0替换","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"displaced mark","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":",如果不存在竞争,则CAS将锁记录空间置为0后,停止CAS操作","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"偏向锁","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向锁的引入","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在多处理器上CAS操作可能开销很大。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"大多数锁不仅不存在竞争,而且往往由同一个线程使用。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"使单独一个线程获取锁的开销更低。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"代价是使另一个线程获取锁开销增大。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向锁加锁过程","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"锁对象第一次被线程获取时,VM把对象头中的标志位设为101,即偏向模式","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"同时使用CAS把获取到这个锁的线程ID记录在对象的mark word中,如果CAS成功,则持有偏向锁的线程以后每次进行这个锁相关的同步块时,不再进行任务同步操作,只进行比较Mark word中的线程ID是否是当前线程的ID","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向锁的解锁过程","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"当另外一个线程去尝试获取这个锁时,偏向模式结束。根据锁对象目前是否处于被锁定状态,撤销偏向后恢复到未锁定或轻量级锁定状态","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"VM会停止持有偏向锁的线程(实际上,VM不能停止单一线程,而是在安全点进行的操作)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"遍历持有偏向锁的线程的栈,找到锁记录空间,将displaced mark 写入到最旧的锁记录空间,其他的写0","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"更新锁对象的mark word。如果被锁定,则指向最旧的锁记录空间,否则,填入未锁定值。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"偏向锁的特点:","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"偏向于第一个获取锁的线程:","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"mark word","attrs":{}},{"type":"text","text":"的Tag中增加一位","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"001表示无锁状态\n101表示偏向或可偏向状态(thread ID ==0 == unlock)\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"通过CAS来获取偏向锁","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"对于持有锁的线程接下的锁获取和释放开销非常小(仅仅判断下,不需要CAS同步操作)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果另一个线程锁定了偏向锁对象,则偏向锁收回,升级为轻量级锁(增加了另一个线程获取锁的开销)。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章