Search code examples
javaconcurrencysynchronizedconcurrentmodificationsynchronized-block

ConcurrencyException


private static HashMap<String, FileInfo> sFileInfoObjectList = new CacheLinkedHashMap<String, FileInfo>();

public static synchronized FileInfo getFileInfoForProvider(...) {
 FileInfo foundFileInfo = null;

 (...)

 foundFileInfo = sFileInfoObjectList.get(hashEntryKey);

 (...)

 sFileInfoObjectList.put(hashEntryKey, foundFileInfo);

 (...)
}

public static synchronized void removeFileInfoForProvider(final int providerId) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            Iterator<Entry<String, FileInfo>> it = sFileInfoObjectList.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, FileInfo> pair = it.next();
                FileInfo info = pair.getValue();
                if (providerId == info.mProvider) {                            
                    it.remove();
                }
            }
        }
    };
}

I am getting a ConccurentModificationException in the run() method. I tried following and it did not work:

public void run() {
    synchronized(sFileInfoObjectList) {
        Iterator<Entry<String, FileInfo>> it = sFileInfoObjectList.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, FileInfo> pair = it.next();
            FileInfo info = pair.getValue();
            if (providerId == info.mProvider) {                            
                it.remove();
            }
        }
    }
}

Solution

  • The run() is not in a synchronized block because it is run on another thread. You could use synchronized in your run method but it would be much simpler to use a concurrent collection which does throw this error. E.g. ConcurrentHashMap.

    BTW: I wouldn't start a thread each time as it could be more expensive than just iterating over the collection. I would use a thread pool, or do it in the current thread.


    Replace your method with this

    public static void removeFileInfoForProvider(final int providerId) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                removeFileInfoForProvider0(providerId);
            }
        };
        thread.start();
    }
    
    static synchronized void removeFileInfoForProvider0(final int providerId) {
        Iterator<Entry<String, FileInfo>> it = sFileInfoObjectList.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, FileInfo> pair = it.next();
            FileInfo info = pair.getValue();
            if (providerId == info.mProvider) {                            
                it.remove();
            }
        }
    }