在原子变量上使用 volatile
在变量上使用 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());
}
}
Using volatile on a variable reduces the risk of memory consistency error (Please correct me if this reveals some holes in my understanding of any relevant concept). So in the following example even though the variable c1 is volatile, still the occurrence of memory constancy error results in c1 becoming 15 or sometimes 14 in the output rather then the correct output 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());
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你是对的。因为 ++ 不是原子操作,所以当线程与另一个线程同时读取/递增/写入值时,您仍然可以获得不一致的结果。
对于此类情况,请考虑使用 AtomicInteger。
You are correct. Because ++ is NOT an atomic operation you can still get inconsistent results where a thread reads/increments/writes a value at the same time as another thread.
Consider using AtomicInteger for cases like this.
原子性只是图片的一部分。还有可见性。如果更改非易失性(且非同步)变量值,则不能保证其他线程及时看到更改,或者根本无法看到更改。
Atomicity is only part of the picture. There is also visibility. If a non-volatile (and non-synchronized) variable value is changed, other threads are not guaranteed to see the change in time, or at all.
检查 http://www.javabeat.net/tips/169 -volatile-keyword-in-java.html 用于了解 volatile 的作用。它避免了中间线程缓存,但无论如何,在非原子操作中读取其值和更新可能会丢失更新。
Check http://www.javabeat.net/tips/169-volatile-keyword-in-java.html for understanding what volatile does. It avoids the intermediate thread cache but anyway there can be the lossed update from reading its value and updating in a non atomic operation.