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

How to initialize a hashTable with safe-thread object as value?

HashTable 是线程安全的集合,但使用 ArrayList(不是线程安全的)初始化它是否会危及整个线程安全方面的价值?

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

此外,我计划将 ArrayLists 的每个操作都包装在 synchronized 块中,以防止在使用任何方法操作时出现任何竞争条件。

但我还没有将 HashTable 中的 ArrayLists 声明为同步列表,这是通过以下代码实现的

 Collections.synchronizedList(new ArrayList<>())

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

如何确定 HashTable 中的 ArrayLists 是线程安全的?

将线程安全的 ArrayList 传递给 hashTableput() 方法就足够了吗?(甚至不用担心 HashTable 的构造函数?)因此 HashTable 的 put() 方法甚至无法识别我是否传递了 thread-safe/unsafe 参数?

注意:线程安全是一项要求。否则我不会选择这个实现。

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

CopyOnWriteArrayList 是一个很好的替代品。

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

只有这样才能保证Hashtable or ConcurrentHashMap are thread-safe is to wrap it in a way that prevents anyone from adding something that you don't control. Never expose the Map itself or any of the Lists contained in it to other parts of your code. Provide methods to get snapshot-copies if you need them, provide methods to add values to the lists, but make sure the class wrapping the map is the one that will create all lists that can ever get added to it. Iteration over the "live" lists in you map will require external synchronisation (as metioned in the JavaDocs of synchronizedList).

中的值

HashtableConcurrentHashMap 都是 thread-safe,因为并发操作不会使它们处于无效状态。这意味着例如如果您使用相同的键从两个线程调用 put,其中一个将 return 另一个插入的值作为 "old" 值。但是,如果没有一些外部同步,你当然无法提前判断哪个是第一个,哪个是第二个。

虽然实现方式完全不同:Hashtable 和由 Collections.synchronizedMap(new HashMap()); 编辑的同步 Map return 的相似之处在于它们基本上添加了 synchronized大多数方法的修饰符。如果您有很多主要读取但只是偶尔修改映射的线程(即对锁的高争用),这可能效率低下。 ConcurrentHashMap 提供更细粒度的锁定:

Retrieval operations (including get) generally do not block

这可以产生更好的性能,具体取决于您的用例。我还提供了具有强大搜索功能的更丰富的 API 和 bulk-modification-operations.