Linked Questions

Popular Questions

ConcurrentModificationException for synchronized list

Asked by At

It's been awhile since I wrote some Java so this code is probably crap:

 synchronized (this){
      for (IAsyncCb cb : this.getOnDrainCbs()) {
         cb.run(this);
      }
  }

I am getting this warning:

Exception in thread "Thread-4" java.util.ConcurrentModificationException
        at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
        at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
        at org.ores.Queue$1.lambda$done$0(Queue.java:310)
        at java.base/java.lang.Thread.run(Thread.java:844)

Really, Java should print something WarningEvent instead of Exception, since it doesn't stop execution, but that's besides the point. This seems to be the culprit:

  public void onDrain(IAsyncCb cb) {
    this.drainCBs.add(cb);
  }

but it's working with a synchronized collection:

  private List<IAsyncCb> drainCBs = Collections.synchronizedList(new ArrayList<>());

but if I change it to:

  public synchronized List<IAsyncCb> getOnDrainCbs() {
    return this.drainCBs;
  }

  public void onDrain(IAsyncCb cb) {
    this.getOnDrainCbs().add(cb);
  }

then I no longer get the ConcurrentModificationException. Anybody know why using a synchronized getter would prevent the exception, even when it's already a synchronized list?

In other words, I would have assumed that using Collections.synchronizedList() would have prevented this kind of exception/warning, and would have obviated the need for a synchronized getter.

Related Questions