【趣话编程】一个Java对象的回忆录:那些被锁住的日子

简介: 上期我们跟着一个Java对象一起回忆了垃圾回收的相关内容,今天让我们一起去看看那些被锁住的日子。

原文链接

偏向锁

“喂,别动啊,让我检查下你的lock位状态”,不知什么时候我竟然又睡着了,睁开眼睛,一位线程大哥正蹲在我的旁边,摸着我头上的MarkWord
image.png
“lock位是01,不错不错,让我再看看偏向锁标记位,哇,是1,太棒了,支持偏向锁!最后再看看thread位,是0!awesome!看来我来的比较早,还没人跟我抢”,这位线程大哥嘴里一直念叨,我也不知道他在说些什么。
image.png
“来,把你的MarkWord给我,我给你一个新的“,线程大哥手里握着一个64bit的数字,一边说,一边准备来把我头上的MarkWord换掉。
这个时候,我想起小A曾经给我说的话,一下子躲开了,“你要干嘛”,我紧张的问到。
“小朋友别紧张,我是3001号线程,执行到了synchronized代码块,需要给你这个对象加下偏向锁。来,听话,把MarkWord给我”,一边说一边带着邪魅的微笑。
“我的MarkWord不能给你随便改,改坏了怎么办”
“别怕,一会儿用完了我会给你恢复的”
我将信将疑,知道胳膊拗不过大腿,只好把头伸了过去,“你动手吧”
线程大哥执行了一个CAS操作,把我的MarkWord交换了,然后高高兴兴的离开了。
[为防抄袭,手动插入文字水印,敬请谅解。本文来自微信公众号:编程技术宇宙]

重偏向

过了一小会儿,又来了一个线程小姐姐。
“Hi,小朋友你好,我是3002号线程,现在我要来锁定你,让我检查下你的lock位状态吧”,这个线程小姐姐声音很温柔。
image.png
“lock位是01,Good!让我再看看偏向锁标记位,呀!是个1,糟糕”,小姐姐皱起了眉头。
“发生什么事了?”我开口问到。
“被3001号线程那家伙抢在前头了,把你给锁定了”
“咦,你怎么知道3001号线程来过”
“你的MarkWord里面高54位记录了他的线程指针,指向的就是3001那家伙”,小姐姐指了指我的头说到。
我看了看,果然如此,“您别着急,3001号线程大哥说了,一会儿用完会给我恢复的,要不您稍等一会,坐下休息休息?”
“不用了,我又检查了下,3001号小子已经退出同步块代码了,我可以重偏向,这下你是我的了!哈哈”,说完,又把我的MarkWord换了,我看了下,thread字段这次指向了她。
随后的一段时间里,3001号线程大哥和3002号线程小姐姐来来回回给我锁了好几次,不过每次都错开了时间,一直没什么矛盾,直到······

轻量级锁

“糟糕!”,3002号线程小姐姐又来了。
“怎么了?”
“这一回3001这小子还在执行synchronized中的代码,我没法重偏向了”,小姐姐有点不开心的样子。
“那怎么办呢?”,我弱弱的问到。
小姐姐没有理我,在一旁忙碌着。
“总算弄好了,我刚向内务总管线程VMThread提交申请,把偏向锁升级成轻量级锁”,说完小姐姐擦了擦额头的汗。
话音刚落,VMThread大爷就来了,他也伸手准备要换我的MarkWord。
image.png
“啊,不行,我被3001号线程大哥锁住了,MarkWord里面写着他的地址呢,你可不要乱改啊”,说完我躲到了一边。
“孩子别怕,3001号线程现在在安全点,被挂起来了,现在有别人也要来锁定你,偏向锁不够用了,咱得升级成轻量级锁。”,VMThread大爷一脸慈祥的说到。
“你们这样背着3001号线程私自改了不会出问题吗?”,我还是有点担心。
“别担心,只是升级一下,并不会改变你的归属。看到3001号线程的栈了吗,我在那里申请到了一个LockRecord,会把你的MarkWord保存过去,LockRecord中的Obj也会指向你。”,大爷继续说道。
“那需要我做什么呢?”
“来,我给你换一个新的MarkWord”,说完就又给我换掉了。我看了一下,lock位变成了00,剩下的位变成了一个指针,刚好指向了他刚刚说的那个LockRecord
image.png
VMThread大爷走后,3002号线程小姐姐开始我旁边转来转去,每过一会儿过来看一眼,就这样来来回回好几次,我终于忍不住了。
“你这是在干嘛啊,在我面前晃来晃去,我头都晕了”
1.gif
“我这是在自旋,等3001号那家伙来释放,话说那家伙怎么还不来”,小姐姐说完看了一眼手里的计数器。

重量级锁

“不行了,不能再等了,白白让我浪费了这么多时间”,小姐姐等得有些生气,“来,我再给你换个MarkWord”
“这怎么又要换了?”,我有点纳闷儿。
“那家伙久等不来,我不能一直这么等着,占着CPU不干活啊,得给你膨胀成重量级锁”,说完,小姐姐又执行了一个CAS操作,把我的MarkWord修改了。
我看了一下,这一次,lock位变成了10,剩下的位指向的地方好像不是一个LockRecord。
image.png
“小姐姐,我这MarkWord中指向的是个什么啊?”,我忍不住问到。
“那是一个ObjectMonitor对象,哦,也就是我说的重量级锁啊”,一边说,一边准备了一个ObjectWaiter对象,把自己线程地址放了进去,随后将这个对象放入monitor对象的等待列表中。
“小姐姐,为什么要叫重量级锁呢?”
“因为一会儿我就得去线程切换,交出占用的CPU,让给别人,等你被释放之后我再来,这一来一去的挺折腾的,所以叫重量级锁嘛。好了,小朋友,我得去休息了,回头见”,说完就离开了。

hashcode

小姐姐前脚刚走,又双叒来了一个线程大叔。
“你是不是也要来锁定我啊?”,这一次我先开口了。
“小朋友,你误会了,我要计算下你的HashCode,等下要放到你的MarkWord中”,大叔蹲在一旁手里计算着什么。
image.png
“怎么又要放在MarkWord里,你们就不能换个地方存吗?”,我有点不耐烦了。
“你为什么要说又呢”,大叔问到。
“刚才有几个线程把我的MarkWord改了又改,现在你又要来...”
听完我的话,大叔停下了手里的计算,凑近了看了看我的MarkWord,“呀!lock位是10,你被锁了啊,没事儿,我可以把HashCode保存在ObjectMonitor里面,好了,你继续玩吧,我就不打扰你了”
大叔说完转身离开,留下我独自一个对象,不多时我又睡着了~
未完待续······

彩蛋

不知怎么回事,3001号线程大哥始终未曾过来将我释放,时间就这样一分一秒的流逝。
直到3003号线程的到来,才知道发生了什么······
预知后事如何,请关注后续精彩······

来源 | 编程技术宇宙
作者 | 轩辕之风

相关文章
|
14天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
13天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
12天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
15天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
5天前
|
Java API 数据库
Java 反射机制:动态编程的 “魔法钥匙”
Java反射机制是允许程序在运行时访问类、方法和字段信息的强大工具,被誉为动态编程的“魔法钥匙”。通过反射,开发者可以创建更加灵活、可扩展的应用程序。
|
6月前
|
安全 Java 程序员
Java并发编程中的锁机制与优化策略
【6月更文挑战第17天】在Java并发编程的世界中,锁是维护数据一致性和线程安全的关键。本文将深入探讨Java中的锁机制,包括内置锁、显式锁以及读写锁的原理和使用场景。我们将通过实际案例分析锁的优化策略,如减少锁粒度、使用并发容器以及避免死锁的技巧,旨在帮助开发者提升多线程程序的性能和可靠性。
|
5月前
|
存储 缓存 Java
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
54 0
|
7月前
|
安全 Java 编译器
Java并发编程中的锁优化策略
【5月更文挑战第30天】 在多线程环境下,确保数据的一致性和程序的正确性是至关重要的。Java提供了多种锁机制来管理并发,但不当使用可能导致性能瓶颈或死锁。本文将深入探讨Java中锁的优化策略,包括锁粗化、锁消除、锁降级以及读写锁的使用,以提升并发程序的性能和响应能力。通过实例分析,我们将了解如何在不同场景下选择和应用这些策略,从而在保证线程安全的同时,最小化锁带来的开销。
|
7月前
|
安全 Java 开发者
Java并发编程中的锁优化策略
【5月更文挑战第30天】 在Java并发编程领域,锁机制是实现线程同步的关键手段之一。随着JDK版本的发展,Java虚拟机(JVM)为提高性能和降低延迟,引入了多种锁优化技术。本文将深入探讨Java锁的优化策略,包括偏向锁、轻量级锁以及自旋锁等,旨在帮助开发者更好地理解和应用这些高级特性以提升应用程序的性能。
|
7月前
|
安全 Java API
Java 8中的Stream API:简介与实用指南深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第29天】本文旨在介绍Java 8中引入的Stream API,这是一种用于处理集合的新方法。我们将探讨Stream API的基本概念,以及如何使用它来简化集合操作,提高代码的可读性和效率。 【5月更文挑战第29天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何通过不同的锁机制和同步策略来保证多线程环境下的数据一致性,同时避免常见的并发问题如死锁和竞态条件。文章还将介绍现代Java虚拟机(JVM)针对锁的优化技术,包括锁粗化、锁消除以及轻量级锁等概念,并指导开发者如何合理选择和使用这些技术以提升应用的性能。