可以在没有迭代的情况下获取、放置和删除 HashMap 中的元素导致 ConcurrentModificationException?

Can get, put & remove elemetn in HashMap without iteration cause ConcurrentModificationException?

我有一个静态 hashMap,与多个线程共享。我根本没有迭代地图,只是使用 getputremoveConcurrentModificationException安全吗?

方法看起来像这样

private static Map<Long, Integer> TRACKER = new HashMap<Long,Integer>();
public static void track(Long tid, boolean b) {
        if (b) {
            if (TRACKER.containsKey(tid)) {
                TRACKER.put(tid, TRACKER.get(tid) + 1);
            } else {
                TRACKER.put(tid, 1);
            }
        } else {
            Integer n = TRACKER.get(tid);
            if (n != null) {
                n = n -1;
                if (n == 0) {
                    TRACKER.remove(tid);
                } else {
                    TRACKER.put(tid, n);
                }
            }
        }
    }

如果多个线程在 HashMap 上执行 getputremove 操作,没有适当的同步,size() 报告丢失 /丢失条目,意外的 NPE ...甚至可能发生无限循环。

HashMap documentation 说 -

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. (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.) ...

谢谢斯蒂芬。

Is it safe from ConcurrentModificationException?

ConcurrentModificationException 是安全的。该异常仅由使用常规迭代器或拆分器迭代(在某种意义上)地图或其视图之一的方法抛出。

但是,由于 HashMap 不是线程安全的 class,如果您在没有适当的外部外部同步的情况下从多个线程使用它,可能会发生不好的事情。这些包括(按不良程度增加的顺序)

  1. size() 方法报告错误值。
  2. 条目暂时或永久神秘消失。
  3. 可能的 NPE 和其他未经检查的异常。
  4. 由于多个线程在哈希链中创建循环的不幸操作序列,可能会出现无限循环。

您的示例代码 不安全 ... 但您不会得到 "fast fail" ConcurrentModificationException。相反,您可能会在 "random" 次出现难以重现的莫名其妙的错误。