Java:关于Java关键字" volatile"的混淆在JLS

时间:2015-08-10 02:26:32

标签: java multithreading volatile

JLS中有一个例子 关于关键字 volatile

一个线程重复调用方法一,另一个线程调用方法二。

  class Test {
        static volatile int i = 0, j = 0;
        static void one() { i++; j++; }
        static void two() {
            System.out.println("i=" + i + " j=" + j);
        }
    }
  

这允许方法1和方法2同时执行,但是保证对i和j的共享值的访问完全出现次数,并且以完全相同的顺序出现,因为它们似乎在程序执行期间发生每个帖子的文字。因此,j的共享值永远不会大于i的共享值,因为对i的每次更新必须在更新为j之前反映在i的共享值中。但是,对于方法二的任何给定调用都可能会观察到j的值远远大于为i观察到的值,因为方法一可能在方法二获取i的值的时刻之间执行多次。方法二获取j值的那一刻。

有些问题:

  • shared values是什么意思?
  • 我们应该在哪种情况下使用volatile?(因为"方法二的任何给定调用都可能会观察到j的值远远大于为i&#34观察到的值;)

我从其他文章中了解到,如果有多个核心或处理器(我认为这一点不止一个缓存),那就是“非易失性”#34;价值可能会导致问题。

有什么问题?为什么?

2 个答案:

答案 0 :(得分:3)

共享值是static int i,j,因为它们可以在许多不同的线程之间共享(这是静态的定义)。当多个线程访问同一个变量时,应该使用volatile。同样的争论是,只有当一个线程写入值时才会使用volatile,而其他人读取它是因为i += 5之类的操作不是原子的,除非你使用AtomicInteger(这应该是首选的,尽管有一个更高的开销)。

当一个线程写入该值并且从该值读取一个(或多个)线程时,您应该使用volatile的原因是因为没有volatile关键字,该线程将缓存该值并将使用缓存中的值可能与实际值不一致。 volatile关键字强制每个线程不缓存该值并访问该值的实际内存位置。

答案 1 :(得分:1)

此上下文中的共享值是由多个线程操纵的变量。

实现(编译器或CPU)可以重新排序对非易失性变量的访问,因此结果可能与“天真的”预期结果(即顺序执行)不一致。使用volatile,您可以保证对程序命令的执行顺序完成对共享变量的访问。

当同时完成对变量的冲突访问时,您需要易失性,而不保护锁,信号量或其他互斥原语。如果至少有一个是写(读/写或写/写),并且它们不是由互斥原语或程序顺序排序,则对同一变量的两个操作是冲突的。