指令重排序是个比较复杂、觉得有些不可思议的问题,同样是先以例子开头(建议大家跑下例子,这是实实在在可以重现的,重排序的概率还是挺高的),有个感性的认识
/**
* 一个简单的展示Happen-Before的例子.
* 这里有两个共享变量:a和flag,初始值分别为0和false.在ThreadA中先给 a=1,然后flag=true.
* 如果按照有序的话,那么在ThreadB中如果if(flag)成功的话,则应该a=1,而a=a*1之后a仍然为1,下方的if(a==0)应该永远不会为
* 真,永远不会打印.
* 但实际情况是:在试验100次的情况下会出现0次或几次的打印结果,而试验1000次结果更明显,有十几次打印.
*/
public class SimpleHappenBefore {
/** 这是一个验证结果的变量 */
private static int a=0;
/** 这是一个标志位 */
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
//由于多线程情况下未必会试出重排序的结论,所以多试一些次
for(int i=0;i<1000;i++){
ThreadA threadA=new ThreadA();
ThreadB threadB=new ThreadB();
threadA.start();
threadB.start();
//这里等待线程结束后,重置共享变量,以使验证结果的工作变得简单些.
threadA.join();
threadB.join();
a=0;
flag=false;
}
}
static class ThreadA extends Thread{
public void run(){
a=1;
flag=true;
}
}
static class ThreadB extends Thread{
public void run(){
if(flag){
a=a*1;
}
if(a==0){
System.out.println("ha,a==0");
}
}
}
}
例子比较简单,也添加了注释,不再详细叙述。
什么是指令重排序?有两个层面:
在虚拟机层面,为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则(这规则后面再叙述)将程序编写顺序打乱——即写在后面的代码在时间顺序上可能会先执行,而写在前面的代码会后执行——以尽可能充分地利用CPU。拿上面的例子来说:假如不是a=1的操作,而是a=new byte[1024*1024](分配1M空间)`,那么它会运行地很慢,此时CPU是等待其执行结束呢,还是先执行下面那句flag=true呢?显然,先执行flag=true可以提前使用CPU,加快整体效率,当然这样的前提是不会产生错误(什么样的错误后面再说)。虽然这里有两种情况:后面的代码先于前面的代码开始执行;前面的代码先开始执行,但当效率较慢的时候,后面的代码开始执行并先于前面的代码执行结束。不管谁先开始,总之后面的代码在一些情况下存在先结束的可能。
在硬件层面,CPU会将接收到的一批指令按照其规则重排序,同样是基于CPU速度比缓存速度快的原因,和上一点的目的类似,只是硬件处理的话,每次只能在接收到的有限指令范围内重排序,而虚拟机可以在更大层面、更多指令范围内重排序。硬件的重排序机制参见《从JVM并发看CPU内存指令重排序(Memory Reordering)》
重排序很不好理解,上面只是简单地提了下其场景,要想较好地理解这个概念,需要构造一些例子和图表,在这里介绍两篇介绍比较详细、生动的文章《happens-before俗解》和《深入理解Java内存模型(二)——重排序》。其中的“as-if-serial”是应该掌握的,即:不管怎么重排序,单线程程序的执行结果不能被改变。编译器、运行时和处理器都必须遵守“as-if-serial”语义。拿个简单例子来说,
public void execute(){
int a=0;
int b=1;
int c=a+b;
}
这里a=0,b=1两句可以随便排序,不影响程序逻辑结果,但c=a+b这句必须在前两句的后面执行。
从前面那个例子可以看到,重排序在多线程环境下出现的概率还是挺高的,在关键字上有volatile和synchronized可以禁用重排序,除此之外还有一些规则,也正是这些规则,使得我们在平时的编程工作中没有感受到重排序的坏处。
程序次序规则(Program Order Rule):在一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说应该是控制流顺序而不是代码顺序,因为要考虑分支、循环等结构。
监视器锁定规则(Monitor Lock Rule):一个unlock操作先行发生于后面对同一个对象锁的lock操作。这里强调的是同一个锁,而“后面”指的是时间上的先后顺序,如发生在其他线程中的lock操作。
volatile变量规则(Volatile Variable Rule):对一个volatile变量的写操作发生于后面对这个变量的读操作,这里的“后面”也指的是时间上的先后顺序。
线程启动规则(Thread Start Rule):Thread独享的start()方法先行于此线程的每一个动作。
线程终止规则(Thread Termination Rule):线程中的每个操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值检测到线程已经终止执行。
线程中断规则(Thread Interruption Rule):对线程interrupte()方法的调用优先于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测线程是否已中断。
对象终结原则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。
正是以上这些规则保障了happen-before的顺序,如果不符合以上规则,那么在多线程环境下就不能保证执行顺序等同于代码顺序,也就是“如果在本线程中观察,所有的操作都是有序的;如果在一个线程中观察另外一个线程,则不符合以上规则的都是无序的”,因此,如果我们的多线程程序依赖于代码书写顺序,那么就要考虑是否符合以上规则,如果不符合就要通过一些机制使其符合,最常用的就是synchronized、Lock以及volatile修饰符。
以上这篇浅谈java指令重排序的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
# java
# 指令重排序
# Java并发编程变量可见性避免指令重排使用详解
# Java指令重排序在多线程环境下的处理方法
# Java指令重排在多线程环境下的解决方式
# Java中volatile防止指令重排
# Java volatile如何实现禁止指令重排
# Java指令重排引发问题及解决方案
# 多线程
# 不符合
# 都是
# 这是一个
# 情况下
# 给大家
# 两句
# 在前面
# 永远不会
# 指的是
# 自己的
# 检测到
# 的是
# 这是
# 是个
# 有两个
# 在这里
# 有个
# 地说
# 那就
相关文章:
头像制作网站在线制作软件,dw网页背景图像怎么设置?
建站VPS推荐:2025年高性能服务器配置指南
如何在万网ECS上快速搭建专属网站?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
,制作一个手机app网站要多少钱?
北京专业网站制作设计师招聘,北京白云观官方网站?
C++中引用和指针有什么区别?(代码说明)
动图在线制作网站有哪些,滑动动图图集怎么做?
如何选择适配移动端的WAP自助建站平台?
重庆市网站制作公司,重庆招聘网站哪个好?
小说建站VPS选用指南:性能对比、配置优化与建站方案解析
C#怎么创建控制台应用 C# Console App项目创建方法
沈阳制作网站公司排名,沈阳装饰协会官方网站?
重庆网站制作公司哪家好,重庆中考招生办官方网站?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
制作企业网站建设方案,怎样建设一个公司网站?
如何获取PHP WAP自助建站系统源码?
在线制作视频的网站有哪些,电脑如何制作视频短片?
怀化网站制作公司,怀化新生儿上户网上办理流程?
广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?
建站之星代理如何优化在线客服效率?
建站上市公司网站建设方案与SEO优化服务定制指南
安徽网站建设与外贸建站服务专业定制方案
建站主机选择指南:服务器配置与SEO优化实战技巧
红河网站制作公司,红河事业单位身份证如何上传?
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
网站按钮制作软件,如何实现网页中按钮的自动点击?
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?
如何快速搭建FTP站点实现文件共享?
建站之星如何一键生成手机站?
Swift中循环语句中的转移语句 break 和 continue
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?
nginx修改上传文件大小限制的方法
香港服务器网站推广:SEO优化与外贸独立站搭建策略
实例解析Array和String方法
建站三合一如何选?哪家性价比更高?
武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?
如何在VPS电脑上快速搭建网站?
建站之星代理如何获取技术支持?
上海网站制作网站建设公司,建筑电工证网上查询系统入口?
专业网站制作服务公司,有哪些网站可以免费发布招聘信息?
如何在阿里云完成域名注册与建站?
如何快速生成橙子建站落地页链接?
手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?
c# F# 的 MailboxProcessor 和 C# 的 Actor 模型
网站专业制作公司,网站编辑是做什么的?好做吗?工作前景如何?
全景视频制作网站有哪些,全景图怎么做成网页?
建站之星安装路径如何正确选择及配置?
用v-html解决Vue.js渲染中html标签不被解析的问题
*请认真填写需求信息,我们会在24小时内与您取得联系。