所以我坚持使用一个线程敌对单例实现,它将Iterator返回给HashSet。 我有两个线程 - 有时 - 同时访问此迭代器以加载数据。我称之为luckyThread和unluckyThread。 ONE (unluckyThread)抛出ConcurrentModificationException。
问题:可以安全地假设其他线程一切顺利吗? 具体来说:luckyThread加载的数据是否没有腐败? (发生这种情况的时间系统一直很好,除了不幸的线程) 不要认为这个问题需要任何代码示例,但如果需要,我很乐意提供它们。
更新:(没有详细说明)只要其中一个线程加载一个干净的数据集,系统就可以了。而且不用说我修复了这个问题,但这让我想到从这些异常中恢复,我没有在网上找到任何具体内容。
答案 0 :(得分:5)
如果你查看ConcurrentModificationException的文档,它会明确指出:
请注意,通常情况下无法保证快速失败的行为 说话,在场的情况下不可能做出任何硬性保证 不同步的并发修改。失败快速操作投掷 ConcurrentModificationException是尽力而为的。因此,它 编写一个依赖于此异常的程序是错误的 它的正确性:只能使用ConcurrentModificationException 检测错误。
相反,您可能应该使用其他一些机制来确保没有并发访问(例如在访问底层HashSet时使用synchronized
- 块与单例)。
答案 1 :(得分:3)
抛出异常是因为后备存储已更改,这使得该存储上的迭代器的任何使用都容易受到异常的影响。如果写得不好,甚至可以在单线程应用程序中进行。在你的情况下,你的两个线程都没有过于幸运,因为两者都会在发生变化时遇到这种异常。
即使没有更改你的底层HashSet,让两个线程访问你的迭代器也会导致不确定的行为,因为两者都会改变迭代器的内部状态,更不用说在最好的情况下每个线程都会抓取不同的项目从你的集合。
代码本身并不安全,必须重写以使用线程安全Set并且不共享线程之间的迭代器。
答案 2 :(得分:3)
这绝对不安全。您目前正在查看最佳案例场景:一个线程获得ConcurrentModificationException
。它可能比这更糟糕。并发访问时未定义HashSet
的行为。我不确定HashSet
上的迭代器有多稳定,但快速查看来源让我觉得它可能会出错。如果在迭代期间重新键入键,则很有可能以无限循环结束。
结论:要么同步对迭代器的访问,要么创建集合的副本(在同步块中),要么更改为线程安全集合。
答案 3 :(得分:0)
另一种方法是使用ConcurrentHashMap代替HashMap。在多线程应用程序中访问ConcurrentHashMap时,您不需要具有同步块。