使用volatile关键字

sap*_*sap 4 java volatile

据我所知,如果我们将变量声明为volatile,那么它将不会存储在本地缓存中.每当线程更新值时,它都会更新到主存储器.因此,其他线程可以访问更新的值.

但是在下面的程序中,volatile和non-volatile变量都显示相同的值.

不会为第二个线程更新volatile变量.任何人都可以解释为什么testValue没有改变.

class ExampleThread extends Thread {
    private int testValue1;
    private volatile int testValue;
    public ExampleThread(String str){
      super(str);
    }
    public void run() {
    if (getName().equals("Thread 1 "))
    {
        testValue = 10;
        testValue1= 10;
        System.out.println( "Thread 1 testValue1 : " + testValue1);
        System.out.println( "Thread 1 testValue : " + testValue);
    }
    if (getName().equals("Thread 2 "))
    {
        System.out.println( "Thread 2 testValue1 : " + testValue1);
        System.out.println( "Thread 2 testValue : " + testValue);
    }               
}
}

public class VolatileExample {
    public static void main(String args[]) {
        new ExampleThread("Thread 1 ").start();
        new ExampleThread("Thread 2 ").start();
    }
}
Run Code Online (Sandbox Code Playgroud)


output:
Thread 1 testValue1 : 10
Thread 1 testValue : 10
Thread 2 testValue1 : 0
Thread 2 testValue : 0
Run Code Online (Sandbox Code Playgroud)

Pét*_*rök 7

您的变量仅限于一个线程,因此没有其他线程访问它们.因此volatile没有区别.

如果您声明了它们static,它们将在不同的线程之间共享.但是,即使这样,您也可能无法观察到易失性和非易失性变量之间的差异.引自Java Concurrency in Practice,第二章.3.1.4:

volatile变量的可见性效果超出了volatile变量本身的值.当线程A写入易失性变量并且随后线程B读取相同的变量时,在写入易失性变量之前,A可见的所有变量的值在读取volatile变量后变为B可见.因此,从内存可见性的角度来看,编写volatile变量就像退出synchronized块一样,读取volatile变量就像进入synchronized块一样.

在您的情况下,代码首先修改volatile变量,因此另一个变量的更新值可能对另一个线程不可见.到现在为止还挺好.

但是,由于您要从修改它们的同一个线程中打印出变量的值,因此无论如何都不会看到任何差异.

Update2:试试这个修改过的版本(注意:我还没有测试过):

class ExampleThread extends Thread {
    private static int testValue1;
    private static volatile int testValue;
    private int newValue;

    public ExampleThread(String str, int newValue){
      super(str);
      this.newValue = newValue;
    }
    public void run() {
      for (int i = 0; i < 10; i++) {
        System.out.println(getName() + " testValue1 before update: " + testValue1);
        System.out.println(getName() + " testValue before update: " + testValue);
        testValue = i * newValue;
        testValue1 = i * newValue;
        System.out.println(getName() + " testValue1 after update: " + testValue1);
        System.out.println(getName() + " testValue after update: " + testValue);
        sleep(10);
      }               
    }               
}

public class VolatileExample {
    public static void main(String args[]) {
        new ExampleThread("Thread 1 ", 5).start();
        new ExampleThread("Thread 2 ", 10).start();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:关于静态字段的可见性 - 再次来自同一个主题(第16.2.3节):

[...]静态初始化的对象在构造期间或被引用时不需要显式同步.但是,这仅适用于构造状态 - 如果对象是可变的,则读取器和写入器仍然需要同步以使后续修改可见并避免数据损坏.