Android - ConcurrentModificationException - read and delete on different threads

I am having problems with ConcurrentModificationException when working with streams and HashMaps. And I would like some ideas to read and modify the HashMap at the same time, if possible. Or is it the best solution for queuing one after another?

HashMap example:

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

      

What the thread does (mostly):

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

      

While the stream is running, I process the Items and remove them from the HashMap when finished, one by one. I sometimes get this exception, which I think is removing an element from the HashMap when it tries to serialize it with Gson. I am starting a thread to speed up the whole process as the work done on the thread can take 2-4 seconds and I don't want to block the main thread.

I tried to solve this problem by using ConcurrenthashMap and cloning the HashMap inside the thread so that it doesn't block the Hashmap as shown below. But I haven't found a working solution for it.

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

      

Stack trace:

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)

      

+3


source to share


2 answers


If you look at your stack trace, you can see that a is HashMap

changing concurrently and Gson is iterating over (note the calls com.google.gson

before HashMap$EntryIterator.next

.

By the looks of it, on line 825 from DataFragment.java

you are passing an object ( Job

I assume?) Containing HashMap

to Gson, but you are simultaneously updating that value HashMap

to a separate thread. You probably just need to find where this one is HashMap

declared internally Job

and change it to ConcurrentHashMap

one that won't throw ConcurrentModificationException

.



You can never safely work with HashMap

or other non-thread related objects in multiple threads. Your options are a) using thread-safe data structures, or b) using external synchronization or locking mechanisms to ensure thread safety.

0


source


Use java iterator to avoid concurrent modification exception.



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

      

0


source







All Articles