我们是否需要使 ConcurrentHashMap 易失性?

2022-08-31 20:59:54

我们有一个由2个线程读取和写入的共享。ConcurrentHashMap

class Test {
    private ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();

    Object read() {
        return map.get(object);
    }

    void write(Object key, Object object) {
        map.put(key, object);
    }
}

我们是否需要使映射易失性,以便读者线程能够尽快看到一个线程的写入?

有没有可能一个线程中的地图放置不会被另一个线程看到或看到得很晚?

相同的问题。HashMap


答案 1

如果你能做到,那就去做吧。如果你不能做到,那么是的,你需要做它。 适用于字段分配,如果不是,则有可能(至少根据 JMM)一个线程写入 CHM 字段可能对另一个线程不可见。重申一下,这是现场分配,不使用 CHM。finalfinalvolatilevolatilefinalConcurrentHashMap

话虽如此,你真的应该做到。final

我们是否需要使映射易失性,以便读者线程能够尽快看到一个线程的写入?

如果您所说的写入是使用CHM本身的突变方法(如或)完成的,则使场不稳定不会产生影响。所有内存可见性保证都在 CHM 内完成。putremove

有没有可能一个线程中的地图放置不会被另一个线程看到或看到得很晚?相同的问题。HashMap

不适用于 .如果同时使用普通,请不要使用。请参见: http://mailinator.blogspot.com/2009/06/beautiful-race-condition.htmlConcurrentHashMapHashMap


答案 2

volatile 在读取和写入相应变量时应用发生在语义之前。

可以声明一个字段,在这种情况下,Java 内存模型确保所有线程都看到变量的一致值 (§17.4)。volatile

它与变量值引用的对象无关。您没有修改变量,因此您不应该*遇到任何问题,除非(*)您没有安全地发布在线程之间共享的对象。Test

正如 Lii 在 coments 中建议的那样,假设您没有采取正确的预防措施,通过 、 或某些其他同步机制,JMM 允许在对象被其构造函数完全初始化之前提供对对象的引用。因此,您的一个线程可以在初始化字段之前尝试使用它(例如,它会看到 )。从这个意义上说,代码可能会中断。finalvolatilemapnull

有没有可能一个线程中的地图放置不会被另一个线程看到或看到得很晚?

这是不可能的,因为javadoc指出,方法引入了适当的内存障碍,ConcurrentHashMap

检索反映最近完成的更新操作在其开始时保持的结果。(更正式地说,给定密钥的更新操作与报告更新值的该密钥的任何(非空)检索具有发生之前关系。

HashMap但是,它不是线程安全类型。 在这里也无济于事,因为它控制对变量的更改,而不是变量引用的对象。您需要外部同步来保护并调用 .volatileputgetHashMap


推荐