这篇文章主要讲解了“Java指令重排序在多线程环境下如何处理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java指令重排序在多线程环境下如何处理”吧!指令重排在单线程环境下有利于提高程序的执行效率,不会对程序产生负面影响;在多线程环境下,指令重排会给程序带来意想不到的错误。下面给出一个能够百分之百复原指令重排的例子。reader
方法仅在flag
变量为true时向控制台打印变量a
的值。writer
方法先执行变量a
的赋值操作,后执行变量flag
的赋值操作。如果按照上述分析逻辑,那么控制台打印的结果一定全为1。假如代码未发生指令重排,那么当flag
变量为true时,变量a
一定为1。上述代码中关于变量a
和变量flag
在两个方法类均存在指令重排的情况。通过观察日志输出,发现有大量的0输出。当writer
方法内部发生指令重排时,flag
变量先完成赋值,此时假如当前线程发生中断,其它线程在调用reader
方法,检测到flag
变量为true,那么便打印变量a
的值。此时控制台存在超出期望值的结果。使用关键字new创建对象时,因其非原子操作,故存在指令重排,指令重排在多线程环境下会带来负面影响。使用关键字new创建一个对象,大致分为一下过程:在栈空间创建引用地址以类文件为模版在堆空间对象分配内存成员变量初始化使用构造函数初始化将引用值赋值给左侧存储变量针对上述示例,假设第一个线程进入synchronized代码块,并开始创建对象,由于重排序存在,正常的创建对象过程被打乱,可能会出现在栈空间创建引用地址后,将引用值赋值给左侧存储变量,随后因CPU调度时间片耗尽而产生中断的情况。后续线程在检测到instance
变量不为空,则直接使用。因为单例对象并为实例化完成,直接使用会带来意想不到的结果。使用原子类将一组相关联的变量封装成一个对象,利用原子操作的特性,有效回避指令重排免费云主机域名问题。原子类应该是解决多线程环境下指令重排的首选方案,不仅通俗易懂,而且线程间使用的非重量级互斥锁,效率相对较高。当一组相关联的变量发生指令重排时,使用原子操作类是比较优的解法。指令重排不仅限于Java程序,实际上各种编译器均有指令重排的操作,从软件到CPU硬件都有。指令重排是对单线程执行的程序的一种性能优化,需要明确的是,指令重排在单线程环境下,不会改变顺序程序执行的预期结果。上面讨论了两种典型多线程环境下指令重排,分析其带来负面影响,并分别提供了应对方式。对于关联变量,先封装成一个对象,然后使用原子类来操作对于new对象,使用volatile关键字修饰目标对象即可synchronized锁通过互斥锁,有序的保证线程访问特定的代码块。代码块内部的代码正常按照编译器执行的策略重排序。尽管synchronized锁能够回避多线程环境下重排序带来的不利影响,但是互斥锁带来的线程开销相对较大,不推荐使用。synchronized 块里的非原子操作依旧可能发生指令重排感谢各位的阅读,以上就是“Java指令重排序在多线程环境下如何处理”的内容了,经过本文的学习后,相信大家对Java指令重排序在多线程环境下如何处理这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是百云主机,小编将为大家推送更多相关知识点的文章,欢迎关注!
相关推荐: ZooKeeper集群操作及集群Master选举搭建启动的方法
这篇“ZooKeeper集群操作及集群Master选举搭建启动的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“ZooKeeper集群操作及集…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。