指令重排序会破坏happens-before原则吗

问题描述

今天阅读"深入理解java虚拟机"时,P333,关于happens-before解释,有这么一段:引用

解决方案

引用线程A: readConfig(); //读取配置 init=true; 线程B: while(init){ useConfig(); //使用配置 } 由于线程A可能会发生指令重排序,所以线程B使用的配置可能尚未加载,所以使用volatile解决此问题。 比如说,在readConfig();里有N多的指令要执行指令abcdinit=true;如果abcd和init变量都没有关系,就是不存在happens-before关系的话,若果被重排,比如说可能变成abinit=true;cd此时其实c,d还没有执行 但是b线程里init=true;已经成立了。。。所以就执行 useConfig(); 了 然后会出错
解决方案二:
引用也就是说,指令只关注线程内部指令abcd和变量init是否存在happens-before关系,不会考虑对其他线程的影响可以这么认为吧,一般来说每个线程都是有一块独立的内存区域,把共享的变量存一个副本进行操作,对其他线程的顺序是不可见的,使用了volatile相当于禁止了在线程内部内存或者是寄存器操作共享数据,而是直接在共享的主存上进行,相当于每个线程能看见别的线程对主存的操作,所以就能够保证读写顺序一般指令顺序的优化都是编译器和cpu干的事情
解决方案三:
引用happens-before是因,良好同步是果。有确定结论吗?happens-before其实就是说逻辑时钟的同步,如果满足happens-before,在执行的逻辑上必然是可以满足同步的楼主可以搜一下 分布式同步的资料 时钟同步算法思想都是一样的
解决方案四:
引用"时间上顺序与先行发生原则之间基本没有太大关系,所以我们衡量并发安全问题的时候不要受时间顺序的干扰,一切必须以先行发生原则为准。"是这样的,它的意思不是说没有关系,是说在不影响happen-before的条件下,我们可以交换指令的顺序。也就是说,happen-before的原则还是要成立的,不能被破坏。比如有四条指令happen-before关系如下,a发生在b之前 c发生在d之前A - > BC -> D那么 以下的指令顺序都是正确的,因为都不违反happen-before的条件 a,b,c,d a,c,b,dc,a,b,dc,d,a,b
解决方案五:
只要不影响结果(也不可能会影响,不然是bug了),就不会违背happens-before原则。。可以在并发编程实践中有happens-before的描述。。
解决方案六:
就我的理解来说,happens-before不是原则,而是由良好同步的代码所带来的结论,不是所有的代码都会有happens-before的那几个结论,也就是说,happens-before是结论。因为命名的原因,这因果关系很容易搞混。同时,happens-before并不以时间作为衡量标准,happens-before的那几个结论才是衡量标准。不知道这样的解释你理解否,因为我之前有过同样的疑惑(http://www.iteye.com/problems/71027),但是这关系确实有些绕。

时间: 2024-08-03 15:28:25

指令重排序会破坏happens-before原则吗的相关文章

从JVM并发看CPU内存指令重排序(Memory Reordering)

这两天,我拜读了 Dennis Byrne 写的一片博文Memory Barriers and JVM Concurrency (中译文内存屏障与JVM并发). 文中提到: 对主存的一次访问一般花费硬件的数百次时钟周期.处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为了性能重新排列待定内存操作的顺序.也就是说,程序的读写操作不一定会按照它要求处理器的顺序执行. 这段话是作者对内存屏障重要性的定义.通过cache降低内存延迟,这句话很好理解.但后面那句"为了性能重排序内存

java-eclipse中的debug和指令重排序

问题描述 eclipse中的debug和指令重排序 Java代码经过优化会有指令重排序,那么eclipse的debug按照代码从上到下的顺序执行又是如何做到的 解决方案 debug的程序都是不做优化的,编译的时候使用的是javac -g,除了优化之外,还有assert只在debug的时候才会执行.其实这不是eclipse这样,其他ide也一样 解决方案二: debug按照代码从上到下的顺序执行,是因为debug模式下的代码是未经过优化的. 你不设置断点,debug和Release运行对比一下.

JVM的重排序

感谢同事[沐剑]的投稿 重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段.重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境. 在并发程序中,程序员会特别关注不同进程或线程之间的数据同步,特别是多个线程同时修改同一变量时,必须采取可靠的同步或其它措施保障数据被正确地修改,这里的一条重要原则是:不要假设指令执行的顺序,你无法预知不同线程之间的指令会以何种顺序执行. 但是在单线程程序中,通常我们容易假设指令是顺序执行的,否则可以想象程序会发生

关于java重排序的问题

问题描述 今天看<java并发编程实战>看到重排序的地方P28,这个例子始终都没有成功,代码如下:publicclassNoVisibility{privatestaticbooleanready;privatestaticintnumber;privatestaticclassReaderThreadextendsThread{publicvoidrun(){while(!ready){Thread.yield();}System.out.println(number);}}publicst

深入理解Java内存模型(二)——重排序

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/java-memory-model-2 数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性.数据依赖分下列三种类型: 名称 代码示例 说明 写后读 a = 1;b = a; 写一个变量之后,再读这个位置. 写后写 a = 1;a = 2; 写一个变量之后,再写这个变量. 读后写 a = b;b = 1; 读一个变量之后,再写这个变量. 上

Java并发编程系列之三:重排序与顺序一致性

前言 在我们编写程序并运行的时候,编译器给我们一个错觉:程序编译的顺序与编写的顺序是一致的.但是实际上,为了提高性能,编译器和处理器常常会对指令进行重排序.重排序主要分为两类:编译器优化的重排序.指令级别并行的重排序和内存系统的重排序.所以我们编写好Java源代码之后,会经过以上三个重排序,到最终的指令序列.我们这里提到的Java内存模型又是什么呢?Java内存模型(后面简称JMM)是语言级别的内存模型,主要用于控制一个共享变量的写入何时对另一个线程可见(后面所有方面都是围绕这点展开的).JMM

深入理解Java内存模型(二) 重排序

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依 赖性.数据依赖分下列三种类型: 上 面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变. 前面提到过,编译 器和处理器可能会对操作做重排序.编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不 会改变存在数据依赖关系的两个操作的执行顺序. 注意,这里所说的数据依赖性仅针对单个处理 器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器 和处理器考

Java内存模型FAQ(四)重排序意味着什么?

原文:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html 第四章 译者:Alex 在很多情况下,访问一个程序变量(对象实例字段,类静态字段和数组元素)可能会使用不同的顺序执行,而不是程序语义所指定的顺序执行.编译器能够自由的以优化的名义去改变指令顺序.在特定的环境下,处理器可能会次序颠倒的执行指令.数据可能在寄存器,处理器缓冲区和主内存中以不同的次序移动,而不是按照程序指定的顺序. 例如,如果一个线程写入值到字段a,然后写入

Java内存访问重排序笔记

关于重排序 重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段. 重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境. As-if-serial语义 as-if-serial语义的意思是,所有的动作(Action)都可以为了优化而被重排序,但是必须保证它们重排序后的结果和程序代码本身的应有结果是一致的. Java编译器.运行时和处理器都会保证单线程下的as-if-serial语义. 比如,为了保证这一语义,重排序不会发生在有数据依赖的操作之