【问题标题】:Which map implementation to use if multiple threads write to a single map如果多个线程写入单个映射,则使用哪个映射实现
【发布时间】:2015-07-21 14:46:27
【问题描述】:

在我的应用程序中,我将使用地图。

  • 多个线程将数据写入此映射。写操作太多。
  • 但是,在每次写入期间,馈送到地图的数据具有不同的键。
  • 在应用程序的任何时候都不会读取地图中的数据。
  • 有时,内容会转储到文件中。

我想知道以下内容:

  1. 在这种情况下,是否需要同步写入方法?
  2. ConcurrentHashMap 是否适合我的需求?
  3. 如果不是,那么在此使用的正确 Map 实现是什么? 案例?

【问题讨论】:

  • "地图中的数据不会在应用程序中的任何位置读取" 然后"偶尔会将内容转储到文件中" - 那么如何在不读取地图的情况下转储到文件?
  • 这两点是不兼容的:“地图中的数据不会在应用程序中的任何点被读取”和“有时内容会被转储到文件中”。如果不读取地图的全部内容,则无法将内容转储到文件中。
  • 您可能还想考虑为每个线程保留一个映射,然后在转储到文件时合并它们。然后,只有当您转储到文件时才会阻止对地图的访问,而不是每次写入都会阻止。
  • 您需要将键序列化到文件中,还是仅将值序列化?
  • ConcurrentHashMap 在答案中得到了很多赞许。它可能适合您的需要,但前提是文件转储永远不会重叠,并且您的地图不需要接受null 作为键。如果您执行任何聚合操作(例如 putAll()clear())并要求它们相对于转储到文件操作而言是原子的,则也不会。

标签: java multithreading dictionary synchronization concurrenthashmap


【解决方案1】:

关注这几点:

  • 在每次写入期间馈送到地图的数据都有不同的键

  • 地图中的数据在应用程序的任何时候都不会被读取

您根本不需要Map。我假设当您声明地图中的数据不会被读取时,您的意思是您没有在做map.get(someKey),而是您将遍历整个地图以将数据存储在文件中(或任何数据您使用的来源)。

这一点:

  • 有时会将内容转储到文件中

强化上述建议。

专注于这一点:

  • 多个线程将数据写入此映射。写入操作太多。

最好的建议是使用BlockingQueue。作为实现,你可以使用LinkedBlockingQueue

如果您使用 Java 同步从 Map 转储数据,并且希望/需要以 Map 的形式恢复此数据,请使用 ConcurrentHashMap。如果这不是您的用例的一部分,因为您将以其他方式从文件中读取数据,请避免使用 Map 并使用 BlockingQueue

【讨论】:

  • 您错过了将整个地图转储到文件中的部分。由于键也是地图的内容,我认为这个答案没有正确解决问题。
  • @user3360241 因为密钥没有任何用途,因为它们总是唯一的,所以那部分真的毫无意义。除非关键是在 Map 的值中找不到的相关数据(除了 OP 没有人知道),否则它看起来并不好。或者,另一方面,如果它有值,则将此 key 存储在值的字段中并保存。同样,Map 选项对于此用例毫无用处。
  • 如果操作想要从另一个应用程序中的文件重建地图怎么办?但正如你所说,在大多数情况下,key 可以嵌入到 value 中,但对于这种情况则不然。
  • @user3360241 因为OP在问题中没有指出这一点,所以没有必要解决它。此外,从文件构建地图并不难。而且 OP 从不谈论序列化机制。
  • @user3360241,阻塞队列是一种非常好的方法。这只是要排队的元素类型的问题。例如,如果需要,可以是经过适当参数化的 Map.Entry
【解决方案2】:

To 1:Map 接口不保证任何同步,尤其是在写入时。查看非并发实现(HashMapHashTableIdentityHashMapLinkedHashMapTreeMapWeakHashMap),所有状态

如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。

至 2 和 3:如果您使用的是 ConcurrentHashMap,则不必担心同步问题。但我同意Luiggi Mendoza's answer:不要使用Map

【讨论】:

    【解决方案3】:
    1. 没有
    2. 是的

    但是我发现这是一个矛盾:

    • 地图中的数据在应用程序的任何时候都不会被读取
    • 有时会将内容转储到文件中。

    如何在不读取文件的情况下转储到文件?

    我认为可以肯定地说 ConcurrentHashMap 无论如何都可以处理这种情况,所以去吧。

    【讨论】:

    • 一些解释会更好,而不是简单地说“是”或“否”。
    【解决方案4】:

    如果你真的需要MapConcurrentHashMap 就是你所需要的。阅读更多关于它的信息here

    【讨论】:

      【解决方案5】:

      正如您所说,ConcurrentHashMap 似乎符合您的要求。它是线程安全的,无需同步整个地图。使用锁完成写入时,读取可能会非常快。

      【讨论】:

        【解决方案6】:

        您的所有密钥都是唯一的,因此您不一定需要同步来确保地图的完整性,但是当您实际写入文件时确实需要它。使用 ConccurentHashMap 或正常的同步映射都适合您。您可以不使用 Map 也可以简单地将键/值存储在某个对象中并将对象存储在同步列表中。

        【讨论】:

        • 拥有不同的键绝不意味着写入地图不需要同步。
        • 引用例如TreeMap's Javadoc如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,则必须对外同步
        • @JohnBollinger 和图灵:是的,我明白这一点。我的问题是,如果要插入的所有键都是唯一的,并且 Map 仅用于书写目的,那么可能的危害是什么?例如:从一个线程写入可能对另一个线程不可用.. 足够公平.. 唯一的危害是当您写入文件时,因为您可能看不到所有更新.. 对吗?我错过了什么 ?我同意以上不是一个完美的评论
        • 这不仅仅是看不到更新的问题,尽管应该排除可能的问题。地图的内部状态可能会因不同步的并发更新而损坏。所有不同的键都不能避免这种情况。更一般地说,在没有适当同步的情况下,程序行为没有得到很好的定义。
        • @JohnBollinger:地图损坏的可能性有多大?多个线程写入同一个桶,因为哈希码相同?
        猜你喜欢
        • 2022-01-23
        • 2013-08-26
        • 2018-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-25
        • 2015-01-07
        • 1970-01-01
        相关资源
        最近更新 更多