Java并发编程之验证volatile指令重排-理论篇
Java并发包下的类中大量使用了volatile关键字。通过之前文章介绍,大家已经知道了volatile的三大特性:共享变量可见性;不保证原子性;禁止指令重排后顺序性。通过前面两篇文章我们通过代码验证了前两个特性,本文我们就来验证禁止指令重排保证顺序性。
指令重排序的生活例子
去餐厅吃饭预定位置的的时候。假设要去A餐厅吃饭,A餐厅有前台B、服务员C以及老板D。如果就只有你一个人去吃饭的时候,你给前台或者给服务器或者给老板说一声把2号桌预定了,半小时后过来。餐厅在为了2小时内就你一个人去吃饭。那么OK,没问题,别说等半个小时,就是等一个小时,2号桌还是你的。
但是,如果现在是吃饭高峰期,很多人来吃饭,你给前台说了,前台忙着没有及时给服务员或者没有给老板说,这个时候有个路人甲来吃饭,刚好看到2号桌没人,老板或者服务员就让他就坐2号桌吃饭了。那么,等你过来的时候,2号桌已经有人了。这个时候对于你来说,这个结果就不是你想要的了。
上面案例,如果从计算机执行指令角度来分析的话,你要到2号桌吃饭,这是预期结果。餐厅A就相当于是处理器,前台B就相当于是编译器,服务员C和老板D就是指令和内存系统。如果你预定的时间点不是吃饭高峰期或者没有人去餐厅A吃饭。那么你就相当于是一个线程。就是单线程的。老板、前台、服务员怎么安排都可以。因为只有你一个2号桌肯定是你的。这是单线程情况下。预期结果与实际结果就是一致的。
如果你预定的时间点是吃饭高峰期,很多人来吃饭(很多线程),这个时候为了餐厅效益,无论是前台还是服务员或者是老板都会对你的位置进行重排序。在你没有来的时候,会安排其他人到你预定的位置吃饭。如果其他人在你的位置吃饭,这个时候你再来吃饭,那么实际结果和预期结果就不一样了。这个时候餐厅应该做出相应的赔偿。为了解决这种赔偿问题,老板就想到了一个方案。做个牌子放在客人预定的桌子上。
当前台或者是服务员或者是老板看到餐桌上放的这个牌子,就知道这个位置不能再调动了。其中这个放在餐桌上的牌子就是特殊类型的内存屏障了。
示意图如下:
再来举个更常见的例子:
考试,在考试的时候老师会告诉我们,先做会做的,不会做的放到后面做。假设出题老师出题顺序是1-5,但是考试会根据自己实际情况做题顺序有可能是1、2、4、5、3或者是1、3、4、5、2等等。如果把出题老师看着是写代码的程序员,题目的顺序是代码一行一行的顺序,你的老师会告诉你先做会做的,此时老师就相当于是编译器,会排序一次。然后你自己做的时候又会进行重新排序,你自己就相当于是处理器又排序了一次。
上面两个现实生活中的案例,我们弄明白后,再来看看在计算机中指令重排问题,就很容易理解了。
指令重排
我们程序员编写的代码在JVM执行的时候,为了提高性能,编译器和处理器都会对代码编译后的指令进行重排序。分为3种:
1:编译器优化重排:
编译器的优化前提是在保证不改变单线程语义的情况下,对重新安排语句的执行顺序。
2:指令并行重排:
如果代码中某些语句之间不存在数据依赖,处理器可以改变语句对应机器指令的顺序
如:int x = 10;int y = 5;对于这种x y之间没有数据依赖关系的,机器指令就会进行重新排序。但是对于:int x = 10; int y = 5; int z = x+y;这种的,因为z和x y之间存在数据依赖(z=x+y)关系。在这种情况下,机器指令就不会把z排序在xy前面。
3:内存系统的重排序
通过之前的学习,我们知道了处理器和主内存之间还存在一二三级缓存。这些读写缓存的存在,使得程序的加载和存取操作,可能是乱序无章的。
指令重排序的流程图
通过上面介绍,我们可以知道从程序员写的Java源码到处理器真正实际执行的指令序列,会经历如下图的过程:
执行顺序:
源码编译器优化重排序(第一次排序) 指令重排序(第二次)内存重排序(第三次) 最终指向的指令。
无论是第一次编译器的重排序还是第二、三次的处理器重排序。这些重排序当在多线程的场景下可能会出现线程可见性的问题。
如在多线程的情况下,单例模式就不安全了。
为了解决这个问题,JMM允许编译器在生成指令顺序的时候,可以插入特定类型的内存屏障来禁止指令重排序。
当一个变量使用volatile修饰的时候,volatile关键字就是内存屏障。当编译器在生成指令顺序的时候,发现了volatile,就直接忽略掉。不再重排序了。
示意图:
证明volatile禁止指令重排演示代码,欢迎继续学习下一篇文章
欢迎关注凯哥公众号:凯哥Java(kaigejava)
相关推荐
总的来说,`volatile`关键字在Java并发编程中起到的作用是确保共享变量的即时可见性和防止指令重排,但并不保证操作的原子性。理解并合理使用`volatile`可以有效地提升多线程程序的并发性能,但同时也需要注意它的...
《JAVA并发编程实践》是Java开发人员深入理解并发编程的一本经典著作,由Doug Lea撰写,本书中文版高清完整,包含丰富的书签,便于读者查阅和学习。这本书旨在帮助开发者掌握在Java平台上进行高效、安全并发编程的...
《Java并发编程实战》是Java并发编程领域的一本经典著作,它深入浅出地介绍了如何在Java平台上进行高效的多线程编程。这本书的源码提供了丰富的示例,可以帮助读者更好地理解书中的理论知识并将其应用到实际项目中。...
《Java并发编程实战》这本书是关于Java语言中并发编程技术的经典著作。它详细介绍了如何在Java环境中有效地实现多线程程序和并发控制机制。在Java平台上,由于其本身提供了强大的并发编程支持,因此,掌握并发编程...
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。以下是对标题和描述中所提及的几个知识点的详细解释: 1. **线程与并发** - **线程*...
### Java并发编程:volatile关键字解析 #### 一、内存模型的相关概念 在深入了解`volatile`关键字之前,我们首先需要理解计算机内存模型的一些基本概念。在现代计算机系统中,CPU为了提高执行效率,会将频繁访问的...
在探讨Java并发编程与高并发解决方案的过程中,我们会涉及到一系列核心概念和相关技术。本文将基于文档《Java并发编程与高并发解决方案-学习笔记***.pdf》中提供的内容,来详细阐述并发编程和高并发的基本概念、CPU...
《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...
在Java并发编程中,多线程是核心概念之一。多线程允许程序同时执行多个任务,从而充分利用系统资源,提高程序性能。然而,多线程编程也带来了同步和竞态条件等问题,这需要开发者具备良好的线程管理和同步机制的知识...
《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...
《JAVA并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境下编写高效、安全的代码。 并发编程是现代软件开发中的关键技能,...
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。这份“java并发编程内部分享PPT”显然是一个深入探讨这一主题的资料,旨在帮助开发者...
Java并发编程是软件开发中的一个关键领域,尤其是在大型企业级应用和分布式系统中。通过学习相关的书籍,开发者可以深入理解如何有效地设计和实现高效的多线程应用程序,避免并发问题,如竞态条件、死锁、活锁等。...
Java内存模型(JMM)是并发编程中的核心概念,书中会详细解析其工作原理,包括volatile、final关键字的作用,以及 Happens-Before 规则。理解JMM有助于编写出正确且高效的并发代码。 源码分析部分,书中的附带源码...
这本书是Java并发领域的经典之作,深入浅出地讲解了Java平台上的并发编程原理和最佳实践。书中涵盖了线程安全、同步机制、并发工具类、并发设计模式等多个方面,帮助读者理解如何编写出高效、正确且可维护的并发程序...
在Java编程领域,并发编程是一项核心技能,尤其是在大型系统或分布式应用中,高效地处理多线程和并发操作是至关重要的。"Java并发编程与实践"文档深入剖析了这一主题,旨在帮助开发者理解和掌握如何在Java环境中有效...
根据提供的文件信息,“JAVA并发编程实践 中文 高清 带书签 完整版 Doug Lea .pdf”,我们可以推断出这份文档主要聚焦于Java并发编程的技术实践与理论探讨。下面将从多个角度来解析这个文档可能涵盖的关键知识点。 ...