【问题标题】:Volatile array - memory visibility of the elements易失性数组 - 元素的内存可见性
【发布时间】:2014-06-23 19:52:48
【问题描述】:

考虑一下代码 sn -p

class A {

   private Map<String, Object> taskMap = new HashMap<>();
   private volatile Object[] tasksArray ;

   // assume this happens on thread1 
   public void assignTasks() {
     synchronized(taskMap){
         // put new tasks into map
         // reassign values from map as a new array to tasksArray ( for direct random access )
     }

    }

   // assume this is invoked on Thread2
   public void action(){
       int someindex =  <init index to some value within tasksArray.length>;
       Object[] localTasksArray = tasksArray;
       Object oneTask = localTasksArray[someindex];
       // Question : is the above operation safe with respect to memory visibility for Object oneTask ?
       // is it possible that oneTask may appear null or in some other state than expected ?

   }

}

问题:操作 Object oneTask = localTasksArray[someindex]; 对于 Object oneTask 的内存可见性是否安全? oneTask 是否可能显示为 null 或处于预期之外的其他状态?

我的想法是:

thread2 可能会将oneTask 视为 null 或处于与预期不同的状态。这是因为,即使taskArray 是volatile,并且读取此数组将确保数组本身的正确可见性,但这并不能确保对象oneTask 内部状态的可见性。

【问题讨论】:

标签: java arrays thread-safety volatile memory-visibility


【解决方案1】:

volatile 关键字仅保护字段 taskArray,它是对 Object[] 的引用。每当您读取或写入此字段时,它将具有一致的顺序。但是,这不会扩展到引用的数组或数组引用的对象。

您很可能想要 AtomicReferenceArray。

【讨论】:

    【解决方案2】:

    据我记得(我现在正在研究以确认),Java 仅 保证 volatile 对象本身被刷新到 RAM,而不是该对象的子部分(如数组条目中)或子- 对象的字段(在对象的情况下)。

    但是 - 我相信大多数(如果不是全部)JVM 都将volatile 访问作为内存屏障(参见here 和引用页面The JSR-133 Cookbook for Compiler Writers)。因此,作为内存屏障,这意味着当访问发生时,其他线程的所有先前写入都将从缓存刷新到主内存 - 从而使 所有 内存在那时保持一致。

    不应依赖这一点 - 如果您必须完全控制可见和不可见的内容至关重要,则应按照其他人的建议使用 Atomic 类之一,例如 AtomicReferenceArray。正是因为这个原因,它们甚至可能比volatile 更有效。

    【讨论】:

      【解决方案3】:

      声明一个 volatile ensures 字段,该变量的任何写入都与该值的任何后续(根据同步顺序)同步(因此可见)。请注意,不存在 volatile object 或 volatile array 这样的东西。只有易变的字段。

      因此,在您的代码中,线程 1 将对象存储到数组中与线程 2 从那里读取对象之间没有发生之前的关系。

      【讨论】:

        猜你喜欢
        • 2017-01-17
        • 2013-05-23
        • 2016-05-31
        • 2023-03-21
        • 2013-07-06
        • 2019-11-07
        • 2015-11-03
        • 1970-01-01
        相关资源
        最近更新 更多