phnmnn
phnmnn

Reputation: 13230

Why am I getting a java.util.ConcurrentModificationException in this example?

In the following code sample, I don't understand why foo method throws ConcurrentModificationException. Please help!

private void foo() {
        synchronized (map) {
            if (map != null && !map.isEmpty()) {
                Set<String> it = map.keySet();
                ArrayList<String> delArray = new ArrayList<>();
                for (String key : it) {
                    MapItem mapItem = map.get(key);
                    if (mapItem != null) {
                        long wakeTime = System.currentTimeMillis() - mapItem.getTimestamp();
                        if (wakeTime > MY_THRESHOLD) {
                            if (mapItem.getLock() != null) {
                                mapItem.getLock().release();
                            }
                            delArray.add(key);
                        }
                    }
                }

                if (!delArray.isEmpty()) {
                    for (String key : delArray) {
                        map.remove(key);
                    }
                }
            }
        }
    }

I am getting exception on "for (String key : it) {" line

private static class MapItem {
        private PowerManager.WakeLock lock;
        private long timestamp;

        public MapItem(PowerManager.WakeLock lock, long timestamp) {
            this.lock = lock;
            this.timestamp = timestamp;
        }

        public PowerManager.WakeLock getLock() {
            return lock;
        }

        public long getTimestamp() {
            return timestamp;
        }
    }

Upvotes: 2

Views: 703

Answers (2)

Ke Li
Ke Li

Reputation: 952

I think you didn't put all your code here. Why the constructor if MapItem is WakeLockItem, and what
mapItem.getLock().release(); does? If I remove all PowerManager.WakeLock related code, I can execute it.

    private static class MapItem {
    private long timestamp;

    public MapItem(long timestamp) {
        this.timestamp = timestamp;
    }

    public long getTimestamp() {
        return timestamp;
    }
}

private Map<String, MapItem> map = new HashMap<>();

private void foo() {
    synchronized (map) {
        if (map != null && !map.isEmpty()) {
            Set<String> it = map.keySet();
            ArrayList<String> delArray = new ArrayList<>();
            for (String key : it) {
                MapItem mapItem = map.get(key);
                if (mapItem != null) {
                    long wakeTime = System.currentTimeMillis() - mapItem.getTimestamp();
                    if (wakeTime > 0) {
                        delArray.add(key);
                    }
                }
            }

            if (!delArray.isEmpty()) {
                for (String key : delArray) {
                    map.remove(key);
                }
            }
        }
    }
}

Upvotes: 0

c0der
c0der

Reputation: 18792

You are trying to change map while iterating over it, which is not allowed. ConcurrentModificationException:

If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception

Upvotes: 1

Related Questions