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