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

不可变volatile数组上的javaforeach循环是线程安全的吗?

  •  2
  • Marcel  · 技术社区  · 7 年前

    例子:

    class MyClass
    { 
      volatile String[] m_array = new String[0];
    
      public synchronized void add(String n)
      { m_array = ArrayUtils.add(m_array, n); // atomic replace
      }
    
      public void iterate() // not synchronized!
      { // Do something with each element
        for (String s : m_array)
          System.out.println(s);
      }
    }
    

    我为什么问这个问题?

    通常,Java中的foreach循环扩展为 Iterator :

    Iterator<String> i = m_array.iterator();
    while(i.hasNext())
      ...
    

    在这种情况下 只有一个通道

    但是如果未来的Java实现 优化 (见 foreach vs. for performance )

    for (int i = 0; i < m_array.length; i++)
    { String s = m_array[i];
      ...
    

    这不再是线程安全的,因为对 m_array . 在本例中,临时变量的快照为 m\ U阵列 字段易变时需要。

    上面的优化保证不会以这种方式发生吗?我的代码示例保证是安全的吗?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Marcel    7 年前

    是的,在volatile数组引用上使用增强的for循环是线程安全的 关于易失性场的异步变化。

    理论基础

    但是,如果将来的Java实现优化foreach的原始数组,因为在这种情况下迭代器非常慢呢?

    Iterator Iterable s。Java语言规范保证循环中的每个数组访问在每次迭代中都在同一个实例上,即使 m_array 在迭代过程中已更改。使用以下等效代码指定数组的增强for循环:

    T[] #a = Expression;
    L1: L2: ... Lm:
    for (int #i = 0; #i < #a.length; #i++) {
        VariableModifiersopt TargetType Identifier = #a[#i];
        Statement
    } 
    

    14.14.2 Expression ,对你来说 this.m_array , .