为什么我的两个线程可以通过非易失性字段进行协调?

Why can my two threads coordinate through non-volatile fields?

根据 this specification,两个 java 线程无法通过非易失性字段进行协调。为什么我的代码 运行 没问题?

public class TestVolatileExample {

static int pairCount = 1000;
static VolatileExample[] exps = new VolatileExample[pairCount];
static{
    for(int i = 0;i<pairCount;i++){
        exps[i] = new VolatileExample();
    }
}

@Test
public void test() throws InterruptedException{
    final int valuePair[][] = new int[pairCount][2];
    Thread[] threads = new Thread[pairCount*2];
    for(int i = 0;i<pairCount;i++){
        final int index = i;
        //final VolatileExample exp = new VolatileExample();
        //writer
        Thread writer = new Thread(new Runnable(){
            @Override
            public void run() {
                VolatileExample exp = exps[index];
                int val = new Random().nextInt(100);
                valuePair[index][0] = val;
                exp.set(val);
            }
        });
        writer.start();
        threads[i*2] = writer;
        //reader
        Thread reader = new Thread(new Runnable(){
            @Override
            public void run() {
                VolatileExample exp = exps[index];
                while(!exp.changed()){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //System.out.println("waitting for change...");
                }
                int val = exp.get();
                valuePair[index][1] = val;
            }

        });
        reader.start();
        threads[i*2+1] = reader;
    }
    for(Thread t : threads){
        t.join();
    }
    for(int i = 0;i<pairCount;i++){
        int write = valuePair[i][0];
        int read =  valuePair[i][1];
        System.out.println(write+"," + read);
        Assert.assertEquals(write,read);
    }
 }
}
public class VolatileExample {

  private int x;
  private boolean changed = false; 

  public void set(int x){
      this.x = x;
      this.changed = true;
      System.out.println("changed...");
  }

  public int get(){
      return x;
  }

  public boolean changed(){
      return changed;
  }
}

你看,reader 线程正在等待 VolatileExample 中的值 x,直到标志 属性 被更改。根据Java规范,非易失性属性、'changed'会保存在每个线程各自的缓存中。但是为什么我的程序得到了预期的结果呢?

我开启了1000对读写线程,每个读线程确实读取了写线程写入的值。

我有什么问题吗?

您链接到的页面显示:

The compiler is free to read the field this.done just once, and reuse the cached value in each execution of the loop. This would mean that the loop would never terminate, even if another thread changed the value of this.done.

这意味着您的代码是否有效取决于编译器决定缓存您的变量(无效)还是不缓存(有效)。如果愿意,可以免费这样做,但不必这样做。

所以您的代码可能会或可能不会工作取决于您无法控制的事情。