我已经阅读了几乎所有帖子中的volatile(即使它不是静态的)变量在线程之间共享。当一个线程更新变量时,第二个线程获取更新的值。但是当我在本地机器上运行代码时,运行java 7。它没有给出预期的结果
代码 -
public class StatciVolatile3 {
public static void main(String args[]) {
new ExampleThread2("Thread 1 ").start();
new ExampleThread2("Thread 2 ").start();
}
}
class ExampleThread2 extends Thread {
private volatile 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 2 : 0
Test Value T2: 1
Thread 1 : 0
Test Value T1: 2
Thread 2 : 1
Test Value T2: 1
Thread 1 : 1
Test Value T1: 3
Thread 2 : 2
Test Value T2: 1
Thread 1 : 2
Test Value T1: 4
在这里,我们可以看到线程T2的测试值始终是1.有人可以帮助我理解为什么会发生这种情况吗?
提前致谢!
我的预期结果是 - 这是线程都看到更新的值
Thread 1 : 0
Test Value T1: 2
Thread 2 : 0
Test Value T2: 2
Thread 1 : 1
Test Value T1: 3
Thread 2 : 1
Test Value T2: 3
Thread 1 : 2
Test Value T1: 4
Thread 2 : 2
Test Value T2: 4
答案 0 :(得分:8)
testValue
是一个实例变量,因此每个类的实例都有一个单独的变量副本。您已经创建了两个实例:
new ExampleThread("Thread 1 ").start();
new ExampleThread("Thread 2 ").start();
...每个人都有自己的变量副本。线程2永远不会更新其值,这就是它保持为1的原因。
如果您希望他们共享相同的变量,请将其设为static
:
private static volatile int testValue = 1;
您的陈述:
我已经阅读了几乎所有帖子中的volatile(即使它不是静态的)变量在线程之间共享
...表明你对所读内容的误读或误解。如果线程之间访问同一个变量,则会在线程之间看到对volatile变量的更改,但这并不意味着实例之间将共享实例变量。
有些评论指出'testValue ++'不是原子操作。通常,您应该避免在线程之间共享的volatile变量上执行此类操作。但是,对于有限的示例,这实际上并不是一个问题,因为只有一个线程实际上会改变变量的值。
答案 1 :(得分:3)
我已经阅读了几乎所有帖子中的volatile(即使它不是静态的)变量在线程之间共享
这是一个不正确的陈述。线程之间不共享volatile
实例变量。类的volatile
实例变量确保共享class
的相同实例的所有线程始终会看到volatile
实例变量的更新值该类而不是从缓存中读取值。
要解决问题中发布的特定代码示例的问题,您可以将testValue
标记为static
。
话虽如此,volatile
并不保证原子性。操作testValue++;
不是原子操作,因此如果多个线程可以执行testValue
,则static
声明testValue++
将无法解决问题(这在当前示例中是不可能的) )。在多个线程可以执行testValue++
时解决问题的一种方法是将testValue
声明为AtomicInteger
并将其标记为static
答案 2 :(得分:0)
volatile
关键字确定变量是否将在本地进行线程缓存。
在您的示例中,您期望的结果不会到来,因为两个线程都在处理testValue
父对象的独立实例(在本例中为ExampleThread2
个对象)。如果testValue已经static
,那么结果将如你所愿。
在多CPU环境中,如果在不同CPU上运行的两个线程访问同一个对象,它们将创建两个单独的本地缓存。因此,读/写操作将是不明确的。在这种情况下volatile
出现了。
当我们使用volatile
时,缓存不是在本地创建的,并且两个线程(在不同的CPU上运行)都将在同一个更新的副本上工作(当然需要同步)。