JSR133给Java内存模型定义的happen-before规则

  1. 单线程规则:同一个线程中的每一个操做都happens-before于出如今其后的任何一个操做。app

  2. 对一个监视器的解锁操做happens-before于每个后续对同一个监视器的加锁操做。函数

  3. 对volatile字段的写入操做happens-before于每个后续的对同一个volatile字段的读操做。线程

  4. Thread.start()的调用操做会happens-before于启动线程里面的操做。code

  5. 一个线程中的全部操做都happens-before于其余线程成功返回在该线程上的join()调用后的全部操做。对象

  6. 一个对象构造函数的结束操做happens-before与该对象的finalizer的开始操做。内存

  7. 传递性规则:若是A操做happens-before于B操做,而B操做happens-before与C操做,那么A动做happens-before于C操做。同步

实际上这组happens-before规则定义了操做之间的内存可见性,若是A操做happens-before B操做,那么A操做的执行结果(好比对变量的写入)一定在执行B操做时可见。class

为了更加深刻的了解这些happens-before规则,咱们来看一个例子:变量

//线程A,B共同访问的代码
    Object lock = new Object();
    int a=0;
    int b=0;
    int c=0;
    //线程A,调用以下代码
    synchronized(lock){
        a=1; //1
        b=2; //2
     } //3
     c=3; //4
    //线程B,调用以下代码
    synchronized(lock){  //5
        System.out.println(a);  //6
        System.out.println(b);  //7
        System.out.println(c);  //8
    }

咱们假设线程A先运行,分别给a,b,c三个变量进行赋值(注:变量a,b的赋值是在同步语句块中进行的),而后线程B再运行,分别读取出这三个变量的值并打印出来。那么线程B打印出来的变量a,b,c的值分别是多少?构造函数

根据单线程规则,在A线程的执行中,咱们能够得出1操做happens before于2操做,2操做happens before于3操做,3操做happens before于4操做。同理,在B线程的执行中,5操做happens before于6操做,6操做happens before于7操做,7操做happens before于8操做。而根据监视器的解锁和加锁原则,3操做(解锁操做)是happens before 5操做的(加锁操做),再根据传递性 规则咱们能够得出,操做1,2是happens before 操做6,7,8的。

则根据happens-before的内存语义,操做1,2的执行结果对于操做6,7,8是可见的,那么线程B里,打印的a,b确定是1和2. 而对于变量c的操做4,和操做8. 咱们并不能根据现有的happens before规则推出操做4 happens before于操做8. 因此在线程B中,访问的到c变量有可能仍是0,而不是3.

相关文章
相关标签/搜索