代码之家  ›  专栏  ›  技术社区  ›  Catalin Ghita

如何以安全线程对象为值初始化哈希表?

  •  2
  • Catalin Ghita  · 技术社区  · 6 年前

    HashTable是一个线程安全的集合,但使用ArrayList(不是线程安全的)作为值初始化它会危及整个线程安全吗?

     Hashtable <Employee, ArrayList<Car>> carDealership = new Hashtable<>();
    

    接下来,我计划总结 ArrayLists 在a中 synchronized 使用任何方法操作时,阻止任何竞争条件。

    然而,我还没有将哈希表中的ArrayList声明为同步列表,这是通过以下代码实现的

     Collections.synchronizedList(new ArrayList<>())
    

    显然,当我将ArrayList添加到哈希表时,就会发生这种情况。

    我怎样才能确定 阵列列表 HashTable 线程是否安全?

    足够通过线程安全吗 ArrayList put() 的方法 hashTable 我可以走了吗? (甚至不用担心 散列表 ?)因此 put() 哈希表的方法甚至无法识别我是否在传递线程安全/不安全的参数?

    注:螺纹安全是一项要求。否则我就不会选择这种实现。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Hulk    6 年前

    确保 Hashtable ConcurrentHashMap 线程安全是以一种防止任何人添加您无法控制的内容的方式对其进行包装。切勿暴露 Map 自身或任何 List 它包含在代码的其他部分。如果需要,提供获取快照副本的方法,提供向列表中添加值的方法,但请确保包装映射的类将创建所有可以添加到其中的列表。对地图中的“实时”列表进行迭代将需要外部同步(如所述 in the JavaDocs of synchronizedList )。

    二者都 哈希表 ConcurrentHashMap 是线程安全的,因为并发操作不会使它们处于无效状态。这意味着,例如,如果您调用 put 从具有相同键的两个线程中,其中一个将返回值,另一个作为“旧”值插入。但是,如果没有一些外部同步,您当然无法提前判断哪个是第一个,哪个是第二个。

    虽然实现方式有很大不同,但: 哈希表 和同步的 地图 返回人 Collections.synchronizedMap(new HashMap()); 它们基本上是 synchronized 大多数方法的修改器。如果有很多线程(即锁的高争用性)主要是读取的,但只是偶尔修改映射,那么这可能会很低效。 ConcurrentHashMap 提供更细粒度的锁定:

    检索操作(包括get)通常不会阻止

    这可以产生显著更好的性能,具体取决于您的用例。我还提供了一个更丰富的API,具有强大的搜索和批量修改操作。

        2
  •  0
  •   Aleksandr    6 年前

    是,使用 ArrayList 在这种情况下,它不是线程安全的。您始终可以从表中获取对象并对其进行操作。

    CopyOnWriteArrayList 是一个很好的替代品。

    但仍然存在这样的情况,当一个线程获取(保存在变量中)集合,而另一个线程替换为另一个线程时。
    如果您不打算替换表中的列表,那么这不是问题。