java - 致命异常:主进程 PID:20793 java.util.ConcurrentModificationException
问题描述
该程序是为相应地扫描标签的扫描仪/终端编写的。
发生错误的方法:
public synchronized void generateBlocksWithAfterRFIDRead(Object obj) {
if (searchRFID != null && !isSync) {
HashSet<String> newmarks = (HashSet<String>) obj;
if (newmarks.isEmpty()) return;
int i = 0;
Log.w("Тэг", "В новом наборе всего тегов : " + newmarks.size());
int w = 0;
for (String mark : newmarks) {
Log.w("Тэг", "В новом наборе тэг номер " + i++ + " : " + mark);
if (!(marks == null)) {
if (marks.contains(mark)) {
Log.w("Tag", "Уже содержит такой тэг! Сам тэг : " + mark);
continue;
}
} else {
marks = new HashSet<>();
}
marks.add(mark);
线for (String mark: newmarks) {
据我了解,更改集合时会发生错误,但是如果您一次扫描“大量”标签,一次扫描就会触发此类错误 - 不会发生此类错误。
如何纠正这个错误?如何正确修改集合?
** UPD:** 使用上述方法的方法
public HandlerRFID(RFIDReader reader, SearchResultsActivity activity) {
timeMillis1 = System.currentTimeMillis();
myReader = RFIDReaderSingleton.reader;
acitivityUISearchRes = activity;
readedMarks = new HashSet<>();
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// Gets the image task from the incoming Message object.
// running on mainUi
if (msg.what == StatusesMainUIUpdate.ALL_MARKS_ARE_READED) {
acitivityUISearchRes.generateBlocksWithAfterRFIDRead(msg.obj);
readedMarks = null;
} else {
super.handleMessage(msg);
}
}
};
}
堆栈跟踪:
/com.example.testingodata E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.testingodata, PID: 20793
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:851)
at java.util.HashMap$KeyIterator.next(HashMap.java:885)
at com.example.testingodata.View.SearchResultsActivity.generateBlocksWithAfterRFIDRead(SearchResultsActivity.java:401)
at com.example.testingodata.HandlerRFID$6.handleMessage(HandlerRFID.java:184)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
解决方案
此类的迭代器方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间修改集合,除了通过迭代器自己的删除方法之外,迭代器会抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。
基本上,当您迭代一个集合时,您不应该修改同一个集合 - 您会在 等下看到同样的警告HashMap
。LinkedList
它会导致不可预测的行为,并且您可以做出不同的更改来影响当前状态以不同的方式,所以他们只是让它失败并说“所以不要那样做!”
至于为什么会发生大批量而不是单次扫描:
请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。
因此,很可能更可能会注意到大量更改。它继续说“不要依赖这种行为”,所以你可能应该以不同的方式做事!通常,您只需创建一个单独Set
的(一个空的,或您的原件的副本)并对其进行更改,然后在完成后将其退回或换掉原件。
为了清楚起见,这里的问题是您要在集合上创建一个迭代器(使用for
循环),然后在迭代器在其上运行时修改该集合。我注意到你有synchronized
你的方法,所以如果你也在不同的线程上访问同一个集合,你必须确保你也在以一种线程安全的方式来做 -HashSet
链接谈到了一些关于这些东西
推荐阅读
- angular - PatchVale 到复杂的角度形式
- spring-boot - 在 Spring Boot Eureka Client 中,eureka.client.service-url.defaultZone 是如何工作的以及如何添加新的 eureka 服务器?
- python-3.x - 使用 for 循环在列表中追加元素
- oracle - Oracle Reports 如何从一个 oracle 报告中生成多个输出 pdf
- firebase - 我的带有 Firestore 的 Flutter 应用程序在 Android 上从后台恢复时遇到非常慢的查询
- c# - 如何在生产环境中禁用 Asp.Net Core Web API 中的 400 Bad request 的消息正文?
- python - 如何使用 Django 和 VueJs 解决 CORS?
- xml - ORA-31011: XML 解析失败
- scala - 如何创建一个可以应用于两个包含相同参数的一个或多个类型的泛型函数?
- python - 如何使用 Telethon 导出群组历史记录