HashMap中是否可以在不迭代的情况下获取、添加和删除元素,而不会引发ConcurrentModificationException异常?

3

我有一个静态的hashMap,被多个线程共享。我不会遍历这个map,只是使用getputremove。这样做是否安全,可以避免ConcurrentModificationException异常?

方法看起来像这样:

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);
                }
            }
        }
    }

1
在你这里展示的代码中,没有任何原因会导致ConcurrentModificationException异常。 - undefined
1
没有任何东西会引发并发修改异常...这是不好的,因为并发修改正在发生,并且破坏了一些东西,但它无法找出并抛出异常来警告你。 - undefined
2个回答

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

HashMap文档表示-

请注意,此实现未同步。 如果多个线程同时访问哈希映射,并且其中至少一个线程对映射进行结构性修改,则必须在外部同步它。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已经包含的键关联的值不是结构修改。)...

谢谢Stephen。


1
在阅读这些文档后,你可能可以在没有同步的情况下并发地更新值。但是我无法想象出需要进行检查的机制,以便在更新值时不会意外地放入新值。这将是非常牵强的。 - undefined

3
它是安全的,不会抛出ConcurrentModificationException异常。只有在使用传统迭代器或分割器迭代映射或其一个视图的方法时,才会抛出该异常。但是,由于HashMap不是线程安全的类,如果您在没有适当的外部同步的情况下从多个线程使用它,将会发生不好的事情,包括(按糟糕程度排序):1. size()方法报告错误值;2. 条目神秘地消失,可能是暂时还是永久的;3. 可能发生NPE和其他未经检查的异常;4. 可能由多个线程的不幸操作序列在哈希链中创建循环而导致无限循环。您的示例代码是不安全的...但您不会得到“快速失败”的ConcurrentModificationException异常。相反,在“随机”时间您可能会遇到难以复现的难以解释的错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接