在我读过的几乎所有帖子中 -
如果两个线程(假设线程1和线程2)正在访问同一个对象并更新一个声明为static的变量,则表示线程1和线程2可以创建自己的同一对象的本地副本(包括静态变量) )在它们各自的缓存中,因此线程1更新到其本地缓存中的静态变量不会反映在线程2缓存的静态变量中。静态变量用于对象上下文,其中一个对象的更新将反映在同一个类的所有其他对象中,但不会反映在线程上下文中,其中一个线程更新为静态变量将立即反映所有线程的更改(在他们的本地缓存。)
但是当我在代码片段下面运行时
public class StatciVolatile3 {
public static void main(String args[]) {
new ExampleThread2("Thread 1 ").start();
new ExampleThread2("Thread 2 ").start();
}
}
class ExampleThread2 extends Thread {
private static int testValue = 1;
public ExampleThread2(String str) {
super(str);
}
public void run() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(getName() + " : " + i);
if (getName().compareTo("Thread 1 ") == 0) {
testValue++;
System.out.println("Test Value T1: " + testValue);
}
if (getName().compareTo("Thread 2 ") == 0) {
System.out.println("Test Value T2: " + testValue);
}
Thread.sleep(1000);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
}
输出是 -
Thread 1 : 0
Thread 2 : 0
Test Value T2: 2
Test Value T1: 2
Thread 2 : 1
Test Value T2: 2
Thread 1 : 1
Test Value T1: 3
Thread 2 : 2
Test Value T2: 3
Thread 1 : 2
Test Value T1: 4
由于静态变量不在线程之间共享,因此对于线程2,测试值应始终为1.但情况并非如此。
我读了很多与同一问题相关的其他问题,但我仍然无法理解为什么会发生这种情况。有人可以帮助我理解这个问题。
提前致谢。
答案 0 :(得分:5)
我认为你对记忆模型的危险感到困惑。
静态变量是在线程之间共享 - 您正在阅读的文章并未试图说每个线程都有自己独立的静态变量集。相反,他们一直试图告诉您,如果没有设置适当的内存屏障,不保证在其他线程中可以看到无保护的共享状态修改。这些更改立即可见其他线程完全没问题 - 它只是保证。
答案 1 :(得分:1)
没有保证的时间间隔需要Java实现来使一个线程对另一个线程可见而没有同步或volatile修饰符。
这个想法是让不同的JVM实现者自由决定(因为他们的实现必须在不同的上下文中运行在不同的硬件上),关于他们想要通过缓存,指令重新排序等进行优化的积极程度。如果你将Oracle x86 JVM与ARMv7进行比较,他们做出了截然不同的选择。
发布的代码是一个玩具示例。在现实生活中,最好使用并发集合或消息传递。依赖静态变量形式的共享全局状态是最简单的方法。