java中volatile关键字最简单易懂的例子

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (11)

我正在阅读Java中的volatile关键字,并完全理解它的理论部分。

但是,我正在寻找的是一个很好的案例,它显示了如果变量不是不稳定的,如果是变化的话会发生什么。

下面的代码片段不能按预期工作(来自aioobe

class Test extends Thread {

    boolean keepRunning = true;

    public void run() {
        while (keepRunning) {
        }

        System.out.println("Thread terminated.");
    }

    public static void main(String[] args) throws InterruptedException {
        Test t = new Test();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning set to false.");
    }
}

理想情况下,如果keepRunning不是不稳定的,线程应该继续不断地运行。但是,它在几秒钟后停止。

我有两个基本问题: -

  • 任何人都可以用例子解释volatile吗?不符合JLS的理论。
  • 挥发替代品是否同步?它是否实现原子性?
提问于
用户回答回答于

举个例子:如果没有声明为volatile,那么服务器JVM可以将keepRunning变量提取出循环,因为它没有循环中修改(将其变成无限循环),但客户机JVM不会。这就是为什么你看到不同的结果。

有关易失变量的一般说明如下:

当声明一个字段时volatile,编译器和运行时会注意到这个变量是共享的,并且它的操作不应该与其他内存操作重新排序。易失性变量不会缓存在寄存器或高速缓存中,因为它们对其他处理器是隐藏的,因此读取volatile变量总是会返回任何线程的最新写入

易失性变量的可见性影响超出了易失性变量本身的价值。当线程A写入一个易失性变量,随后线程B读取该变量时,写入易失性变量之前A对A可见的所有变量的值在读取volatile变量后对B变得可见

volatile变量最常用的用法是完成,中断或状态标志:

  volatile boolean flag;
  while (!flag)  {
     // do something untill flag is true
  }

易失变量可用于其他类型的状态信息,但尝试此操作时需要更多注意。例如,volatile的语义不足以使增量操作(count++)原子化,除非可以保证该变量仅从单个线程写入。

锁定可以保证可见性和原子性; volatile变量只能保证可见性。

只有满足以下所有条件时,才可以使用易失性变量:

  • 写入变量不依赖于其当前值,或者可以确保只有单个线程更新该值;
  • 该变量不参与其他状态变量的不变量; 和
  • 由于访问变量时出于其他原因,不需要锁定。

调试提示:确保在调用JVM时始终指定-server JVM命令行开关,即使是开发和测试。服务器JVM执行比客户机JVM更多的优化,例如将变量从循环中提取出来,而这些变量不在循环中修改; 可能在开发环境(客户端JVM)中工作的代码可能会在部署环境(服务器JVM)中崩溃。

这是Java Concurrency in Practice的摘录,您可以找到关于此主题的最佳书籍。

用户回答回答于

Volatile --> Guarantees visibility and NOT atomicity

Synchronization (Locking) --> Guarantees visibility and atomicity (如果正确)

挥发性不能代替同步

只有在更新引用并且不对其执行其他操作时才使用volatile。

例:

volatile int i = 0;

public void incrementI(){
   i++;
}

不会使用同步或AtomicInteger线程安全,因为递增是一个复合操作。

为什么程序不能无限期地运行?

那要看各种情况。在大多数情况下,JVM足够聪明地刷新内容。

正确使用volatile会比较棘手,我会说“如果有疑问,请不要使用它”,而是使用synchronized块。

也:

同步块可以用来代替易失性,但反过来是不正确的

扫码关注云+社区