我正在使用具有 ConcurrentHashMap 形式的对象存储的现有代码。映射中存储了可变对象,供多个线程使用。没有两个线程试图通过设计一次修改一个对象。我担心的是线程之间修改的可见性。
目前,对象的代码在“setter”(由对象本身保护)上具有同步。“getter”上没有同步,成员也不是易变的。对我来说,这意味着无法保证可见性。但是,当一个对象被修改时,它会重新放回映射put()
中(再次调用该方法,相同的键)。这是否意味着当另一个线程将对象拉出映射时,它会看到修改?
我在 stackoverflow、JCIP和 java.util.concurrent 的包描述中对此进行了研究。我想我基本上把自己弄糊涂了……但让我问这个问题的最后一根稻草来自包装描述,它指出:
在将对象放入任何并发集合之前线程中的操作发生在另一个线程中从集合中访问或删除该元素之后的操作。
关于我的问题,“动作”是否包括在 re-put() 之前对存储在地图中的对象的修改?如果所有这些确实导致跨线程的可见性,这是一种有效的方法吗?我对线程比较陌生,非常感谢您的评论。
编辑:
谢谢大家的回复!这是我在 StackOverflow 上的第一个问题,对我很有帮助。
我必须接受ptomli的回答,因为我认为它最清楚地解决了我的困惑。也就是说,在这种情况下,建立“之前发生”关系并不一定会影响修改可见性。关于文本中描述的实际问题,我的“标题问题”构造不佳。ptomli的回答现在与我在JCIP中读到的内容不谋而合:“为确保所有线程都能看到共享可变变量的最新值,读写线程必须在公共锁上同步”(第 37 页)。将对象重新放入映射中不会为修改插入对象的成员提供这种通用锁。
我很欣赏所有改变的技巧(不可变对象等),我完全同意。但是对于这种情况,正如我提到的,由于仔细的线程处理,没有并发修改。一个线程修改一个对象,另一个线程稍后读取该对象(CHM 是对象传送器)。鉴于我提供的情况,我认为 CHM 不足以确保稍后执行的线程将看到第一个的修改。但是,我认为你们中的许多人正确回答了标题问题。