简体   繁体   English

Java 并发:HashMap Vs ConcurrentHashMap 当并发线程只删除元素时

[英]Java Concurrency: HashMap Vs ConcurrentHashMap when concurrent threads only remove elements

i have a main thread that creates a HashMap, adds multiple runnable objects to it and then starts each runnable (passing the HashMap to each).我有一个创建 HashMap 的主线程,向其中添加多个可运行对象,然后启动每个可运行对象(将 HashMap 传递给每个对象)。 The runnable removes its object from the map just before it is about to finish processing.在即将完成处理之前,runnable 从 map 中删除其 object。

I would like to know if there is any reason to use a ConcurrentHashMap (rather than a HashMap) in this case - the only operation the runnables perform on the map is to remove themselves from it.我想知道在这种情况下是否有任何理由使用 ConcurrentHashMap(而不是 HashMap) - 可运行对象在 map 上执行的唯一操作是将自己从中删除。 Is there a concurrency consideration that necessitates the use of ConcurrentHashMap in this case?在这种情况下,是否存在需要使用 ConcurrentHashMap 的并发性考虑?

Main thread主线程

private final Map<Integer, Consumer> runnableMap = new HashMap<>();

Runnable runnable;

for (int i = 1; i <= NUM_RUNNABLES; i++) {
    runnable = new Consumer(i, runnableMap);
    runnableMap.put(i, runnable);
    executionContext.execute(runnable);
}

Consumer implements Runnable消费者实现 Runnable

private final Integer consumerNumber;
private final Map<Integer, Consumer> runnableMap;

public Consumer(int consumerNumber, final Map<Integer, Consumer> runnableMap){
    this.consumerNumber = consumerNumber;
    this.runnableMap = runnableMap;
}

public void run() {
    :::
    // business logic
    :::
    // Below remove is the only operation this thread executes on the map
    runnableMap.remove(consumerNumber);
}

If your reason for doing this is to track thread completion, why not use a CountdownLatch?如果您这样做的原因是跟踪线程完成,为什么不使用 CountdownLatch? Not sure if a HashMap can have concurrency issues only on remove, I recommend use it only if your code will not break on any possible issue, or go with a ConcurrentHashMap.不确定 HashMap 是否只能在删除时出现并发问题,我建议仅当您的代码不会因任何可能的问题而中断时才使用它,或者 go 与 ConcurrentHashMap 一起使用。

You asked about differences between HashMap and ConcurrentHashMap , but there is an additional data structure to consider: Hashtable .您询问了HashMapConcurrentHashMap之间的区别,但还有一个额外的数据结构需要考虑: Hashtable There are differences and trade-offs for each.每个都有差异和权衡。 You will need to evaluate which is the best fit for your intended usage.您需要评估哪个最适合您的预期用途。

  • HashMap is unsynchronized, so if more than one thread can read from or write to it, your results will be unpredictable. HashMap是不同步的,所以如果多个线程可以读取或写入它,您的结果将是不可预测的。 HashMap also permits null as key or value. HashMap还允许 null 作为键或值。

  • Hashtable is synchronized, doesn't support null keys or values. Hashtable表已同步,不支持 null 键或值。 From the Hashtable Javadoc :哈希表 Javadoc

    Hashtable is synchronized.哈希表是同步的。 If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable.如果不需要线程安全实现,建议使用 HashMap 代替 Hashtable。 If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.如果需要线程安全的高并发实现,那么建议使用 ConcurrentHashMap 代替 Hashtable。

  • ConcurrentHashMap is thread-safe, doesn't allow null to be used as a key or value. ConcurrentHashMap是线程安全的,不允许将 null 用作键或值。

The javadoc of HashMap says: HashMap的 javadoc说:

Note that this implementation is not synchronized.请注意,此实现不同步。

If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.如果多个线程同时访问hash map,并且至少有一个线程在结构上修改了map,则必须对外同步。 (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)这通常通过在自然封装 map 的某些 object 上同步来完成.

As mentioned above, deletion is a structural change and you must use synchronization.如上所述,删除是一种结构变化,您必须使用同步。

Furthermore, in the removeNode() method of Hashmap (which is called by the remove() method), the modCount variable is incremented, which is responsible for ConcurrentModificationException .此外,在 Hashmap 的removeNode()方法(由remove()方法调用)中, modCount变量递增,它负责ConcurrentModificationException So you might get this exception if you remove elements without synchronization.因此,如果您在没有同步的情况下删除元素,您可能会遇到此异常。

Therefore you must use a ConcurrentHashMap .因此,您必须使用ConcurrentHashMap

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM