应该使用可以证明"volatile"声明的代码示例

Eri*_*ang 15 java concurrency multithreading volatile

目前我无法理解何时应该使用volatile声明变量.

我已经做了一些研究并且长时间搜索了一些关于它的材料并且知道当一个字段被声明为volatile时,编译器和运行时会注意到这个变量是共享的,并且它上面的操作不应该与其他内存重新排序操作.

但是,我仍然无法理解在什么情况下我们应该使用它.我的意思是,有人可以提供任何示例代码,可以证明使用"volatile"带来的好处或解决问题与不使用它相比?

Sim*_*son 15

这是为什么volatile有必要的例子.如果删除关键字volatile,则线程1 可能永远不会终止.(当我在Linux上测试Java 1.6 Hotspot时,确实如此 - 您的结果可能会有所不同,因为JVM没有义务对未标记的变量进行任何缓存volatile.)

public class ThreadTest {
  volatile boolean running = true;

  public void test() {
    new Thread(new Runnable() {
      public void run() {
        int counter = 0;
        while (running) {
          counter++;
        }
        System.out.println("Thread 1 finished. Counted up to " + counter);
      }
    }).start();
    new Thread(new Runnable() {
      public void run() {
        // Sleep for a bit so that thread 1 has a chance to start
        try {
          Thread.sleep(100);
        } catch (InterruptedException ignored) { 
         // catch block
        }
        System.out.println("Thread 2 finishing");
        running = false;
      }
    }).start();
  }

  public static void main(String[] args) {
    new ThreadTest().test();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @Eric:它给出了我在运行Java 6 JVM的两台不同机器上描述的效果.我想我应该用不同的措辞.只有当volatile关键字存在时,才能保证终止.如果它不存在,JVM可以自由地缓存`running`的值,因此线程1不需要终止.但是,它不会被强制缓存该值. (3认同)
  • @Eric:这正是问题所在:"正确行为"并不等同于"直觉行为".如果重复读取JVM,**可以自由缓存值(例如在CPU的寄存器中),并且每次都不需要从主存储器中读取它.指定变量是`volatile`会禁用此缓存! (2认同)

Jed*_*ith 6

以下是 volatile 必要性的规范示例(在这种情况下是str变量。没有它,hotspot 会将访问提升到循环之外 ( while (str == null)) 并且run()永远不会终止。这将发生在大多数 -server JVM 上。

public class DelayWrite implements Runnable {
  private String str;
  void setStr(String str) {this.str = str;}

  public void run() {
    while (str == null);
    System.out.println(str);
  }

  public static void main(String[] args) {
    DelayWrite delay = new DelayWrite();
    new Thread(delay).start();
    Thread.sleep(1000);
    delay.setStr("Hello world!!");
  }
}
Run Code Online (Sandbox Code Playgroud)