分三个层次吧:
第一层次:单个对象或单个方法层次
a.程序次序规则:可以理解为某一线程中的run方法执行代码,控制流书写在前的一定先行于书写在后的,当然,是广义的书写,考虑循环及判断
b.管程锁定规则:可以理解为被锁的(比如synchronized锁定的)程序块中,执行时间在前的先行于执行时间在后的
c.volatile规则:对一个volatile的写执行先行于时间上位于后面的对这个变量的读操作
d.对象的构造方法先行于finalize的开始
注意:a指的是书写次序、b和c指的是时间次序,这个是不一样的,a指单线程内,而b和c可以看作不同线程内执行的时间前后
第二层次:线程层次:
e.线程启动先行于线程内的执行
f.线程执行先行于线程终止
g.对线程interrupt()方法的调用先行于中断事件的发生
第三个层次:传递原则:
若A先行于B,B先行于C,则A先行于C
符合先行发生关系的逻辑由系统保证多线程的逻辑同步,不需要自己控制
有一个注意点:先行发生关系并不是CPU指令集上的前后顺序,或者说并非实际执行的先后顺序。怎么理解呢?符合先行发生关系的逻辑:A先行于B,以Java为例,JVM保证若B用到了A的数值或结果,则该数值或结果,A一定先行于B,若A、B并无必然的联系,从JVM层面,A、B甚至是可以互换的。再举一个例子可能更好理解一些:代码的书写次序:
{
int a = 1; //A
int b = 2; //B
int c = a + b; //C
}
A先行于C,B也先行于C,A、B并无必然的次序,在字节码层面,执行的次序可能为A->B->C,也可能是B->A->C
在理想的内存模型中,一定是A->B->C,但JVM为了运行优化,可能会对A、B进行交换。
有一个办法可以阻止A、B换位:volatile关键字--被volatile修饰的变量,读不与前交换,写不与后交换
在单线程的环境下,A、B换位并不会影响程序运行结果,而在多线程的环境下,因A、B换位可能会引发一些非所期望的结果,要加倍关注。