我有一个Hashmap,在其中维护不同类型的阅读器到它们各自的java类实现的映射。我有一台支持32种类型的读取器的多线程Java服务器。
您可以假设每隔30秒,每种类型的阅读器在内部都会由1000个对象调用getReader()。
每当我将刷新时间减少到20秒时,它就会偶尔为某些读者引发ConcurrentModificationException。可以吗?
缩短时间段有什么区别?
class Mapper {
Map<String, Reader> READER = new HashMap<>();
public static Reader getReader(type) {
Reader reader = READER.computeIfAbsent(type, k -> new ReaderImpl());
}
}
答案 0 :(得分:3)
如果您的地图可以被多个线程访问,则应使用ConcurrentHashMap。
每当我将刷新时间减少到20秒时,它就会偶尔为某些读者引发ConcurrentModificationException。可以吗?
这可能只是巧合。如果减少时间,则只是使线程更有可能尝试访问该映射并将其破坏,因为您没有使用同步集合。如果您的应用程序运行足够的时间,您也有可能在30秒钟的刷新时间内获得它。调试多线程应用程序很困难,因为您可能认为您的应用程序运行正常-但最终结果是,每1000个错误中有1个错误,因为您以错误的方式处理了多线程。
正如安迪·特纳(Andy Turner)正确指出的那样-您很幸运ConcurrentModificationException
出现了。如果您没有收到任何例外情况,这并不意味着问题就不存在。如果在生产环境中运行时在应用程序中收到此类错误,那将更糟。
答案 1 :(得分:2)
是预期的吗?
如Javadoc of HashMap
中所说(强调他们的意思):
请注意,此实现未同步。。如果多个线程同时访问哈希映射,并且至少一个线程在结构上修改了映射,则必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已经包含的键相关联的值不是结构修改。)
关于是否特别需要ConcurrentModificiationException
,尚不清楚。应该期望的是行为未定义。
如果幸运的话,会发生异常。例外很好:它们告诉您您做错了什么。如果您不那么幸运,它会自动失败。谁知道在您的特定情况下会发生什么?也许它可以正常工作,也许不能。
如果您希望代码正常运行,请使用已记录的类。