从并发修改异常中恢复

Recovering from a concurrent modification exception

所以我坚持使用线程敌对单例实现,returns 一个 HashSet 的迭代器。 我有两个线程 - 有时 - 同时访问此 Iterator 以加载数据。我称它们为 luckyThread 和 unluckyThread。 其中一个 (unluckyThread) 抛出 ConcurrentModificationException。

问题:可以安全地假设其他线程一切正常吗? 具体来说:luckyThread 加载的数据是否没有损坏? (发生这种情况的几次,系统运行得很好,除了不幸的线程) 不要认为这个问题需要任何代码示例,但如果需要,我很乐意提供它们。

更新:(不赘述)只要其中一个线程加载干净的数据集,系统就没问题。不用说我解决了这个问题,但这让我开始考虑从此类异常中恢复,但我没有在网上找到任何具体的内容。

如果您查看 ConcurrentModificationException 的文档,它清楚地指出:

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

相反,您可能应该使用一些其他机制来确保没有并发访问(比如在访问底层 HashSet 时使用 synchronized-block 和单例)。

另一种方法是使用 ConcurrentHashMap 而不是 HashMap。在多线程应用中访问ConcurrentHashMap时不需要同步块。

抛出异常是因为后备存储已更改,这使得在该存储上使用迭代器容易受到异常的影响。如果编写不当,这甚至可能发生在单线程应用程序中。在您的情况下,您的两个线程都不太幸运,因为发生更改时两个线程都可能遇到此异常。

即使不更改底层 HashSet,让两个线程访问迭代器也会导致不确定的行为,因为这两个线程都会更改迭代器的内部状态,更不用说在最佳情况下每个线程都将获取与您的套装不同的物品。

代码并不安全,必须重写以使用线程安全 Set 并且不在线程之间共享迭代器。

这绝对不安全。您目前看到的是最好的情况:一个线程获得 ConcurrentModificationException。情况可能比这更糟。 HashSet 的行为在并发访问下未定义。我不确定 HashSet 上的迭代器有多稳定,但快速查看源代码让我认为它可能会出错。如果密钥在迭代过程中被重新散列,您很有可能会陷入无限循环。

结论:要么同步对迭代器的访问,创建集合的副本(在同步块中),要么更改为线程安全集合。