Search code examples
javaarraylistiteratorconcurrentmodification

Java: Why ConcurrentModificationException occur with a synchronized list?


With this code:

public class SynchroApp {

    public static void main(String[] args) {

        final List<String> unsyList = new ArrayList<>();
        final List<String> syList = Collections.synchronizedList(unsyList);

        TimerTask changeList = new TimerTask() {
            boolean addElem = false;

            @Override
            public void run() {
                // add / remove elements to keep size between 2 and 9
                if (syList.size() < 2)
                    addElem = true;
                else if (syList.size() > 8)
                    addElem = false;
                if (addElem)
                    syList.add(String.valueOf(System.currentTimeMillis()));
                else
                    syList.remove(0);
            }
        };

        TimerTask reverseList = new TimerTask() {
            @Override
            public void run() {
                try {
                    for (String s : syList)
                        s = new StringBuffer(s).reverse().toString();
                } catch (Exception e) {
                    System.out.println("Exception: " + e);
                }
            }
        };

        new Timer().scheduleAtFixedRate(changeList, 0L, 30L);
        new Timer().scheduleAtFixedRate(reverseList, 0L, 20L);
    }
}

Why do I still receive some ConcurrentModificationException on Iterator.next?

EDIT: the update of the list elements in reverseList wasn't working (as explained in comments). This code should work as expected:

for (int i = 0; i < syList.size(); i++)
    syList.set(i, new StringBuffer(syList.get(i)).reverse().toString());

Solution

  • Even most synchronized collections do not like modifications and iterator together. From the API description of Collections.synchronizedList:

    It is imperative that the user manually synchronize on the returned list when iterating over it:

    List list = Collections.synchronizedList(new ArrayList()); ... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }

    Also: You can use the collections from java.concurrent instead. They usually have a more refined synchronization approach.