任务是跟踪一些正在运行的进程。将这些信息保存在内存中很好,所以我使用并发哈希映射来存储这些数据:
ConcurrentHashMap<String, ProcessMetaData> RUNNING_PROCESSES = new ConcurrentHashMap();
安全地将新对象放入映射中一切都很好,问题是这些进程的状态会发生变化,所以我必须不时更新ProcessMetaData
。我使ProcessMetaData
不可变,并使用ConCurrentHashMap
的compute()
方法来更新值,但现在的问题是ProcessMetaData
变得更加复杂,并且保持它不可变很难管理。问题是-只要我只在原子(根据javadoc)compute()
方法中更新ProcessMetaData
-对象可能是可变的,总体上仍然是线程安全的?我的假设正确吗?
只要您只访问传递给compute
的函数中的值,在该函数中进行的修改是安全的。
然而,这是一个毫无意义的理论观点。将值存储到集合或映射中的目的是最终检索和使用它们。这就是问题的开始。
compute
方法返回结果值,就像get
返回当前存储的值一样。一旦调用者开始使用该值,这种使用可能会与映射上的后续compute
操作并发。get
方法甚至可能在compute
操作正在进行时检索该值。允许非阻塞检索操作是ConCurrentHashMap
的主要功能之一。因此,各种竞争条件都可能发生。
因此,使用可变对象并修改compute
中已经存储的值是唯一安全的,当您将map用作只写内存时,这是一个牵强的场景。当您使用不同的线程安全机制以确保在开始读取map之前已完成所有更新时,它可能会起作用,但您的用例似乎不同。