Lui*_*ese 1 java concurrency multithreading
我需要一些帮助才能完全理解运行此代码时发生的情况
public class Main extends Thread {
private static int x;
public static void main(String[] args) {
Thread th1 = new Main("A");
Thread th2 = new Main("B");
th1.start();
th2.start();
}
public Main(String n) {
super(n);
}
public void run() {
while(x<4) { //1
x++; //2
System.out.print(Thread.currentThread().getName()+x+" "); //3
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到了输出
B2 B3 B4 A2
Run Code Online (Sandbox Code Playgroud)
我理解线程A并且B都增加x,然后B循环递增和输出......但为什么是最后输出A2?不应该A看x作为4执行的时候//3?
奖金问题:为什么不能x成为5?
这个问题(略有不同的形式)来自OCP认证的模拟测试,其中解释说x永远不会是5.我很高兴看到我不是唯一不同意的人.
在一个线程中更新变量的值时,其值不一定立即对所有线程可见.这是因为内存保存在CPU缓存中,这使得它的读取和写入速度比主存储器快得多.
将高速缓存的更新内容定期复制到主存储器.只有在发生这种情况时,其他线程才会看到值的更新.
这里发生的是B正在更新值,但该值未被提交给主存储器; 因此,A看到它的旧价值.
如果您创建变量volatile,则所有读取和写入都直接从/到主存储器完成(或者,至少,缓存从/刷新到主存储器),因此对所有线程立即可见对值的更新.
但请注意,您没有执行原子读写操作:另一个线程可以更新x当前线程检查x < 4和递增之间的值x++.因此,您最终可能会得到一个5打印值.
解决此问题的最简单方法是使检查/递增同步:
synchronized (Main.class) {
if (x < 4) {
x++;
System.out.println(...);
}
}
Run Code Online (Sandbox Code Playgroud)
这还具有确保x所有线程中的更新可见性的效果,但也确保只有一个线程可以x一次检查/增加.