【问题标题】:Synchronization of ConcurrentHashMap modifiersConcurrentHashMap 修饰符的同步
【发布时间】:2009-07-05 18:27:47
【问题描述】:

我想在ConcurrentHashMap 的帮助下缓存一些 IO。对二进制文件的修改也应该反映在缓存中。由于缓存将被多个线程使用,所有 IO 操作都是同步的。地图的修改进入同一个synchronized 块。大致如下:

synchronized (file) {
    file.deleteRecord(index)
    map.remove(index);
}

synchronized(file) {
    file.writeRecord(index, record);
    map.put(index, record);
}

mapfile 都是私有的,从缓存类外部看不到。

如果缓存读取,即map.get(index),没有synchronized 块,是否保留线程安全?

正如我之前提到的,ConcurrentHashMap 用作地图实现。

【问题讨论】:

    标签: java concurrency synchronization concurrenthashmap


    【解决方案1】:

    是的。这基本上是ConcurrentHashMap 的重点。来自the documentation

    检索操作(包括get) 一般不会阻塞,所以可能会重叠 带有更新操作(包括 put 并删除)。检索反映了 最近完成的结果 更新操作持有他们的 发作。

    来自package documentation

    并发集合是 线程安全,但不受 单一排除锁。在里面 ConcurrentHashMap 的特例, 它安全地允许任意数量的 并发读取以及可调 并发写入数。

    (当然,这两个文档页面都有更多详细信息。值得仔细阅读。)

    【讨论】:

    • 感谢您确定答案。
    【解决方案2】:

    是的,多亏了 ConcurrentHashMap 实现,线程安全性得以保留到映射引用。

    您存储在地图中的对象是另一回事。

    【讨论】:

      【解决方案3】:

      是的,ConcurrentHashMap 是线程安全的,因此读取(或写入)不需要您进行任何锁定。

      但是,在您的示例中,您最终可能会遇到以下事件序列:

      file.deleteRecord(index);
      map.get(index) // returns the mapping for index even though it has been deleted from file
      map.remove(index);
      

      (writeRecord/put 相同)。在您的情况下,这可能是也可能不是问题。

      【讨论】:

        【解决方案4】:

        好吧,正如这里的每个人所说,这是线程安全的,因为在写入缓存和从缓存读取之间存在先发生关系,但这可能没有意义,具体取决于您希望的其他保证为。

        例如,除非您对文件进行 fsync,否则无法保证将记录写入磁盘,因此您可能无法从磁盘读取记录(取决于文件系统和其他一些因素)。在 writeRecord/deleteRecord 和 map 写入以及从 map 中读取之间也没有 happens-before 关系,因此 JMM 不保证您从 map 中读取了肯定已经写入的内容文件。

        您确实得到保证,写入的 indexrecord 对象的状态将被读取,尽管如果其中任何一个是可变的,那么这可能是一个相当无用的保证。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-04-24
          • 1970-01-01
          • 2010-11-20
          • 1970-01-01
          • 2020-07-22
          • 2020-02-04
          • 2018-09-23
          相关资源
          最近更新 更多