1:Program order rule. Each action in a thread happens-before every action in that thread that comes later in the program order. 同一个线程中,书写在前面的操作happen-before书写在后面的操作。    这个原则是在单线程里面的 。  假设 有   
                                         int x,y; 
                                          x=1; //a 
                                          y=2 //b     那么  a happens-before b; happens-before 是这样定义的,如果B能够看到A动作产生的结果,我们说A happens-before B  。 
还有 java内存模型里面 是有主存和工作内存   那么问题是 这里面 a happens-before b,是指在 工作内存中可以看到 ,还是在主存里面也可以 。   简单来说 ,就是 工作内存 的 y=2 会不会先于x=1 存到主存里面。    比如另外一个线程 在读到 y=2的时候 ,是不是一定 会读到 x=1  。还是 他读到y=2的时候 ,x有可能是0 

解决方案 »

  1.   

    happens-before ordering( 先行发生排序)  
    如何避免这种情况?排序原则已经做到:
    a, 在程序顺序中, 线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
    b, 对象监视器的解锁发生在等待获取对象锁的线程之前.
    c, 对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
    d, 对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
    e, 线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前. 为了实现 happends-before ordering原则, java及jdk提供的工具:
    a, synchronized关键字
    b, volatile关键字
    c, final变量
    d, java.util.concurrent.locks包(since jdk 1.5)
    e, java.util.concurrent.atmoic包(since jdk 1.5)
    …使用了happens-before ordering的例子:
    (1) 获取对象监视器的锁(lock)(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据 (read and load)(3) 执行代码,改变共享变量值 (use and assign)(4) 将工作内存数据刷回主存 (store and write)(5) 释放对象监视器的锁 (unlock)注意: 其中4,5两步是同时进行的.这边最核心的就是第二步, 他同步了主内存,即前一个线程对变量改动的结果,可以被当前线程获知!(利用了happens-before ordering原则)对比之前的例子
    如果多个线程同时执行一段未经锁保护的代码段,很有可能某条线程已经改动了变量的值,但是其他线程却无法看到这个改动,依然在旧的变量值上进行运算,最终导致不可预料的运算结果。 
      

  2.   

    楼上的兄弟 ,又把happens-before 原则说了一遍 ,我的问题是happens-before  的第一条 单线程原则 的一个问题。这里面没有同步。  就是一个顺序原则 ,另一个线程 看到了 他的 b的结果 。那么他是否一定会知道a的结果,如果在这个线程里面a happens-before  b。另一个线程能否看到这个结果。
      

  3.   

    问 这个问题 是因为 ,最近看了 DCL的一些文章。dcl为什么会出错class SomeClass {
    private Resource resource = null;
    public Resource getResource() {
    if (resource == null) {
    synchronized {
    if (resource == null)
    resource = new Resource();
    }
    }
    return resource;
    }
    }
    他的解释是上面的例子不会出现dcl问题。而下面一个例子 
    public MyObject{
    private static MyObect obj;
    private Date d = new Data();
    public Data getD(){return this.d;}
    public static MyObect getInstance(){
    if(obj == null){
    synchronized(MyObect .class){
    if(obj == null)
    obj = new MyObject();//这里
    }
    }
    return obj;
    }
    }
    会出现dcl问题 。因为 如果 线程a运行到“这里”,而线程b,并且调用b。getD();这个时候 可能会有问题,对于"这里"这条语句,线程A还没有离开同步块.
    因为没有"离开同步块"这个条件,线程a的工作区没有强制与主存储器同步,这时工作区中有两个字段
    obj,d 到底先把谁同步到主存储区,没有条件限制,虽然在线程A的工作区obj和d都是完整的,但有JSL
    没有强制不允许先把obj映射到主存储区,如果哪个jvm实现按它的优化方案先把工作存储器中的obj
    同步到主存储器了,这时正好线程B获取了,而d却没有同步过去,那么线程B就获取了obj的引用却找不能obj.getD();我的问题是 按照java的加载类的顺序  是先 按照顺序初始化 语句 ,初始化块 ,然后 执行构造函数 
     那么 Date d = new Data() happens-before new MyObject()执行构造函数 满足单线程的happens-before原则这个时候线程b 既然能看到 new MyObject()的值 ,为什么 看不到 Date d = new Data() 的结果是不是 单线程的 happens-before原则 仅仅是在 工作内存中 
    请高人指点
      

  4.   

    Do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields.
      

  5.   

    Do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields.