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

Java 如何以安全线程对象作为值初始化哈希表?,java,multithreading,arraylist,thread-safety,hashtable,Java,Multithreading,Arraylist,Thread Safety,Hashtable,HashTable是一个线程安全的集合,但是使用ArrayList(它不是线程安全的)作为值初始化它会危及整个线程安全吗 Hashtable <Employee, ArrayList<Car>> carDealership = new Hashtable<>(); 当我将ArrayList添加到哈希表时,显然会发生这种情况 如何确保哈希表中的数组列表是线程安全的 将线程安全的ArrayList传递给hashTable的put()方法就足够了吗?(甚至不用担

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

 Hashtable <Employee, ArrayList<Car>> carDealership = new Hashtable<>();
当我将ArrayList添加到哈希表时,显然会发生这种情况

如何确保
哈希表
中的
数组列表
是线程安全的

将线程安全的
ArrayList
传递给
hashTable
put()
方法就足够了吗?
(甚至不用担心
hashTable
的构造函数)因此,
put()
哈希表的方法甚至无法识别我是否在传递线程安全/不安全的参数


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

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

CopyOnWriteArrayList
是一个很好的替代品

但是仍然存在这样的情况,一个线程获取(保存在变量中)集合,另一个线程替换为另一个。

如果不打算替换表中的列表,则这不是问题。

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

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

但是,实现是完全不同的:
Hashtable
和由
Collections.synchronizedMap(newhashMap())返回的同步
Map
的相似之处在于,它们基本上为大多数方法添加了
synchronized
修饰符。如果您有很多线程(即锁的高争用性)主要是读取的,但只是偶尔修改映射,那么这可能是低效的<代码>ConcurrentHashMap提供了更细粒度的锁定:

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


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

不幸的是,我也必须操作写操作,这种类型的取消资格
CopyOnWriteArrayList
。但是如果不是线程安全的,为什么要在这种情况下使用
ArrayList
?只要我只将同步列表添加到哈希表中,并且特定列表的所有操作都将包含在
同步块中
?@CatalinGhita CopyOnWriteArrayList是线程安全的,使用此列表或同步列表应该没有什么大的区别。我想说的是,如果您要替换某些Emloye的现有列表(您很可能没有这样做),那么这将创建一个非线程安全的案例。请您详细说明为什么替换列表会创建一个非线程安全的案例?这与将线程安全列表添加到HashTable@CatalinGhita想象一下,一个线程将雇员“bob”的列表保存在一个变量中,以便以后处理它。同时,另一个线程将“bob”的列表替换为另一个列表。然后,当第一个线程开始处理它保存的列表时,它将在一个可能过时的列表上运行,对它所做的任何更改都不会反映在表中的列表中。为什么它会在一个过时的列表上工作?只要列表本身标记为synchronizedSide注意:
Hashtable
是线程安全的,但是您不使用它有什么具体原因吗?它提供了一个功能强大得多的API。@Hulk主要是因为HashTable有一个快速失效的迭代器,我也想测试一下。使用ConcurentHashMap仍然无法解决我必须将列表作为值传递的问题。是的,好的,
ConcurrentHashMap
上的迭代会在快照上迭代,并且不会因
ConcurrentModificationException
而失败。我并不是要暗示使用<代码> CONCURNESHASMAP 可以解决你的问题,我只是好奇为什么你要考虑使用古<代码>哈希表< /C> >。在
ConcurrentHashMap
Hashtable
中,确实会出现一个不安全的线程问题,正如下面的答案所述?@Hulk正如我所说,我计划将ArrayList的每个操作包装在一个同步块中,以防止在使用任何方法操作时出现任何争用情况。现在回到问题的答案,海报直面这样一个事实:哈希表实际上可能会使引用处于无效状态。毕竟,我的解决方案是线程安全的吗?
 Collections.synchronizedList(new ArrayList<>())