在变量上使用volatile可以降低内存一致性错误的风险(如果这揭示了我对任何相关概念的理解中的一些漏洞,请纠正我)。因此,在下面的示例中,即使变量c1是易失性的,仍然发生内存持久性错误导致c1在输出中变为15或有时为14,而不是正确的输出16。
class Lunch implements Runnable {
private volatile long c1 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
// synchronized(lock1) { c1 is volatile
c1++;
// }
}
public void run() {
try {
inc1();
Thread.sleep(1000);
inc1();
Thread.sleep(1000);
inc1();
Thread.sleep(1000);
inc1();
inc1();
Thread.sleep(1000);
inc1();
Thread.sleep(1000);
inc1();
Thread.sleep(1000);
inc1();
}
catch(InterruptedException e) {
return;
}
}
public long value() {
return c1;
}
public static void main(String args[]) throws InterruptedException {
Lunch l = new Lunch();
Thread t1 = new Thread(l);
Thread t2 = new Thread(l);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(l.value());
}
}
答案 0 :(得分:6)
你是对的。因为++不是原子操作,所以当线程读取/递增/写入另一个线程的值时,仍然会得到不一致的结果。
考虑使用AtomicInteger这样的情况。
答案 1 :(得分:3)
原子性只是图片的一部分。还有可见性。如果更改了非易失性(和非同步)变量值,则无法保证其他线程能够及时查看更改。
答案 2 :(得分:1)
检查http://www.javabeat.net/tips/169-volatile-keyword-in-java.html以了解volatile的作用。它避免了中间线程缓存,但无论如何都可能会因读取其值并在非原子操作中更新而失败更新。