Android - ConcurrentModificationException - 在不同的线程

时间:2015-06-17 10:13:26

标签: java android multithreading hashmap gson

我在使用线程和HashMaps时遇到ConcurrentModificationException问题。如果可能的话,想要了解如何同时阅读和更改HashMap的一些想法。或者只是将线程排在一起之后的最佳解决方案?

HashMap示例:

protected final ConcurrentHashMap<Long, DataItem> dataItemQueue = new ConcurrentHashMap<Long, RegisterStorageLocationQueueItem>();

线程的作用(基本上):

Job job = new Job(var1, var2, dataItemQueue);
Bundle bundle = new Bundle();
bundle.putSerializable("job", new Gson().toJson(job));
// Saving/sending the serialized data.
storeItemData();

当线程正在运行时,我处理&#34;数据项&#34;并在完成后逐个从HashMap中删除它们。有时我会得到这个异常,我猜是在尝试使用Gson序列化时从HashMap中删除一个项目。我运行该线程以加快整个过程,因为在线程中完成的工作可能需要2-4秒而且我不想锁定主线程。

我试图通过使用ConcurrenthashMap并在线程中克隆HashMap来解决这个问题,这样它就不应该锁定Hashmap,如下所示。但我还没有找到适合它的解决方案。

ConcurrentHashMap<Long, DataItem> newDataItemQueue = new ConcurrentHashMap<Long, DataItem>();
for (Entry<Long, DataItem> entry : this.dataItemQueue.entrySet()) {
    newDataItemQueue.put(entry.getKey(), new DataItem(entry.getValue()));
}

堆栈追踪:

java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792)
at java.util.HashMap$EntryIterator.next(HashMap.java:829)
at java.util.HashMap$EntryIterator.next(HashMap.java:827)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:206)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:99)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:219)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:99)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:219)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:208)
at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:99)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:219)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:99)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:219)
at com.google.gson.Gson.toJson(Gson.java:600)
at com.google.gson.Gson.toJson(Gson.java:579)
at com.google.gson.Gson.toJson(Gson.java:534)
at com.google.gson.Gson.toJson(Gson.java:514)
at com.asd.admin.fragments.DataFragment.saveStateData(DataFragmentment.java:825)

2 个答案:

答案 0 :(得分:0)

如果查看堆栈跟踪,您会看到在Gson迭代时同时修改了HashMap(请注意com.google.gson之前的HashMap$EntryIterator.next次调用。

通过DataFragment.java第825行的外观,您传递的对象(Job,我认为?)包含HashMap到Gson,但您同时更新在单独的线程中HashMap。您可能只需要找到HashMapJob内声明的位置,并将其更改为ConcurrentHashMap,这不会抛出ConcurrentModificationException

您不能永远安全地使用HashMap或跨多个线程的其他非线程安全对象。您的选择是:a)使用线程安全的数据结构或b)使用外部同步或锁定机制来确保线程安全。

答案 1 :(得分:-1)

使用java迭代器来避免并发修改异常。

Map<Long, DataItem> dataItemQueue  = new HashMap<>();
Iterator iterator = dataItemQueue.entrySet().iterator();
while (iterator.hasNext()){
    if( /* your condition goes here */ ){
        iterator.remove();
    }
}