代码之家  ›  专栏  ›  技术社区  ›  asimes

Java volatile循环

  •  9
  • asimes  · 技术社区  · 7 年前

    for (int i = 0; i < someVolatileMember; i++) {
        // Removed for SO
    }
    

    在哪里? someVolatileMember

    private volatile int someVolatileMember;
    

    如果某个线程A正在运行for循环,而另一个线程B则写入 一些挥发性分子

    final int someLocalVar = someVolatileMember;
    for (int i = 0; i < someLocalVar; i++) {
        // Removed for SO
    }
    

    我的问题是 :

    • 只是为了确认线程的迭代次数可以是 如果线程B修改,则在for循环处于活动状态时更改 一些挥发性分子
    • 本地非易失性拷贝足以确保 迭代
    3 回复  |  直到 7 年前
        1
  •  5
  •   M A    7 年前

    你的理解是正确的:

    1. 根据 Java Language Specification volatile 字段确保在不同线程之间执行更新后看到的值之间的一致性:

      Java编程语言提供了第二种机制, 不稳定的 字段,这比出于某些目的锁定更方便。

      不稳定的 ,在这种情况下,Java内存模型确保所有线程都能看到变量的一致值(§17.4).

      不稳定的

    2. 一年一次 final

        2
  •  0
  •   Eugene    7 年前

    首先,这个领域 私有的 (除非你省略了一些可能会改变它的方法)。。。

    这个循环有点无意义,它的编写方式和假设有实际可能改变的方法 someVolatileMember ; 这是因为你可能永远不知道什么时候结束,或者什么时候结束。这甚至可能是一个更昂贵的循环,因为有一个非易失性字段,因为 volatile

    你的解决方案 阅读 一种不稳定的使用,实际上是一种非常常见的模式;它也催生了一个非常常见的反模式:“检查然后行动”。。。你把它读入一个局部变量,因为如果它以后发生了变化,你就不在乎了——你正在使用的是目前最新的副本。所以是的,你在本地复制它的方法很好。

        3
  •  0
  •   diginoise    7 年前

    由于 volatile 从不从大多数本地缓存中获取,但CPU正在采取额外的步骤以确保传播修改(可能是缓存一致性协议、将读取延迟到三级缓存或从RAM读取)。范围内的其他变量也会受到影响 使用变量(这些变量也与主内存同步,但是我在这里不演示)。

    关于性能,以下代码:

    private static volatile int limit = 1_000_000_000;
    
    public static void main(String[] args) {
        long start = System.nanoTime();
        for (int i = 0; i < limit; i++ ) {
            limit--;   //modifying and reading, otherwise compiler will optimise volatile out 
        }
        System.out.println(limit + " took " + (System.nanoTime() - start) / 1_000_000 + "ms");
    }
    

    ... 印刷品 500000000 took 4384ms

    500000000 took 275ms .