根据:
http://www.ibm.com/developerworks/library/j-jtp03304/
在新的内存模型下,当线程A写入易失性变量V,并且线程B从V读取时,在写入V时对A可见的任何变量值现在都保证对B可见.
互联网上的许多地方声明以下代码永远不应该打印"错误":
public class Test {
volatile static private int a;
static private int b;
public static void main(String [] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread() {
@Override
public void run() {
int tt = b; // makes the jvm cache the value of b
while (a==0) {
}
if (b == 0) {
System.out.println("error");
}
}
}.start();
}
b = 1;
a = 1;
}
}
Run Code Online (Sandbox Code Playgroud)
b …
我在这个网站上发现了一些有趣的问题(例如,这个)关于Java中的volatile变量的可见性效果,这些问题源于本段中的Java并发实践:
volatile变量的可见性效果超出了volatile变量本身的值.当线程A写入易失性变量并且随后线程B读取相同的变量时,在写入易失性变量之前,A可见的所有变量的值在读取volatile变量后变为B可见.因此,从内存可见性的角度来看,编写volatile变量就像退出synchronized块一样,读取volatile变量就像进入synchronized块一样.
然而,即使在阅读了本网站相关问题的答案后,我仍然无法完全清楚这种情况,具体而言:
线程A0在线程A 之前写入相同的volatile变量的影响是什么?换句话说:A0写入volatile变量,此值稍后由A(不读取变量)覆盖,然后由B读取.(所以我们有两个来自不同线程(A0和A)的写操作和一个来自第三个线程(B)的读操作).
我可以安全地假设A和B都能保证在A0写入volatile变量之前看到A0可见的所有内容吗?
更新:
这是关于Java内存模型的概念性问题.我知道我无法预测线程A0和A中的易失性变量的写入顺序以及线程B中的读取顺序.然而,仅仅为了便于讨论,让我们说 A0在A开始之前开始很多时间,并且在B开始另一个大量时间之后,让我们做出简化的假设,这足以保证写入和读取按所描述的顺序发生(我知道订单不能仅通过计时来保证,这只是为了避免偏离原始问题而进行的简化).
我正在尝试理解Java的volatile关键字,以便在具有CPU缓存的多线程程序中写入易失性原子变量.
我已经阅读了几个教程和Java语言规范,特别是关于"在订购之前发生"的第17.4.5节.我的理解是,当线程将新值写入volatile变量时,更新的值必须对读取该变量的其他线程可见.对我来说,这些语义可以通过以下两种方式之一实现:
线程可以在CPU缓存中缓存volatile变量,但是必须立即将对缓存中的变量的写入刷新到主存储器.换句话说,缓存是直写的.
线程永远不能缓存volatile变量,必须在主内存中读写这些变量.
本教程(http://tutorials.jenkov.com)中提到的方法1 说:
通过声明计数器变量volatile,对计数器变量的所有写操作都将立即写回主存储器.
方法2在Stackoverflow问题" Java中的易失性变量 "中提到,本教程还提到:
这个变量的值永远不会被线程本地缓存:所有读写都将直接进入"主存"
哪一个是Java中使用的正确方法?
相关的Stackoverflow问题没有回答我的问题:
我正在寻找重新排序代码的事情,甚至可能在多处理器的情况下破坏代码.
这是我在求职面试中提出的一个问题:
你有两个不同的类(实现Runnable)说EvenThread和OddThread.顾名思义,EvenThread只打印偶数,奇数线程只打印奇数,考虑范围为0-100.
class EvenThread implements Runnable {
@Override
public void run() {
for (int i = 0; i <= 10; i += 2) {
System.out.println(i);
}
}
}
class OddThread implements Runnable {
@Override
public void run() {
for (int i = 1; i < 10; i += 2) {
System.out.println(i);
}
}
}
public class EvenOdd {
public static void main(String args[]) {
Thread tEven = new Thread(new EvenThread());
Thread tOdd = new Thread(new OddThread());
tEven.start();
tOdd.start();
}
} …Run Code Online (Sandbox Code Playgroud) 我知道波动是多么有效,但问题是如何特别的.我经常听到那些自称为多线程专家的人,比如关于波动性如何起作用的辩论.
通常对于新手来说解释volatile:每个线程都有自己的cach,其中不同的变量可以存储,但volatile不缓存."专家"开始试图变得聪明,并说它绝对是错误的 - 处理器现金不稳定兑现,但挥发性不能兑现处理器注册.
我找不到有关它的信息.
你能证实或拒绝这个意见吗?
PS我知道java程序员应该知道JMM解决易变的相关问题,但我想得到确切的答案.
concurrency ×5
java ×5
volatile ×4
caching ×2
compiler-bug ×1
cpu ×1
optimization ×1
processor ×1