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

问题描述 投票:1回答:1

根据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;
  }
}

你看,读者线程正在等待VolatileExample中的值x,直到更改了flag属性。根据Java规范,非易失性属性“已更改”将保存在每个线程的相应缓存中。但为什么我的计划得到了预期的结果呢?

我启动了1000对读写线程,每个读取线程都读取了写线程写入的值。

我有什么不对吗?

java multithreading volatile
1个回答
3
投票

您链接的页面显示:

编译器可以自由地读取this.done字段一次,并在循环的每次执行中重用缓存值。这意味着循环永远不会终止,即使另一个线程改变了this.done的值。

这意味着您的代码是否有效取决于编译器是否决定缓存您的变量(不起作用)或不起作用(起作用)。如果它想要它可以自由地这样做,但它没有必要。

因此,您的代码可能会或可能不会起作用,具体取决于您无法控制的内容。

© www.soinside.com 2019 - 2024. All rights reserved.