根据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对读写线程,每个读取线程都读取了写线程写入的值。
我有什么不对吗?
您链接的页面显示:
编译器可以自由地读取this.done字段一次,并在循环的每次执行中重用缓存值。这意味着循环永远不会终止,即使另一个线程改变了this.done的值。
这意味着您的代码是否有效取决于编译器是否决定缓存您的变量(不起作用)或不起作用(起作用)。如果它想要它可以自由地这样做,但它没有必要。
因此,您的代码可能会或可能不会起作用,具体取决于您无法控制的内容。