对于多个类的实例,Volatile关键字无法正常工作

时间:2015-06-04 10:57:51

标签: java multithreading volatile

我已经阅读了几乎所有帖子中的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

3 个答案:

答案 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上运行)都将在同一个更新的副本上工作(当然需要同步)。