Question

Here is my problem:

This piece of code throws a java.util.ConcurrentModificationException, because the Vector listeners is modified while there exists an Iterator for this data structure. The java-doc says that this container offers only a fail-fast iterator.

Is there a possibility to get an Iterator over a standard container like Vector or List in Java that offers me an Iterator, that does not get invalid (is not fail-fast), if there is an element removed during that Iterator "lives"?

I should have the same behavior like the std::list in C++. There the iterator is always valid even if the current iterator is remove. Than the iterator is set to the next element in the list.

public class ClientHandle {
private final Vector<ClientHandleListener> listeners = new Vector<ClientHandleListener>();


public synchronized void  addListener(ClientHandleListener chl) {
    listeners.add(chl);
}

public synchronized void  removeListener(ClientHandleListener chl) {
    listeners.remove(chl); 
}

private void fireConnectionClosed() {
    final ClientHandle c = this;

    final Iterator<ClientHandleListener> it = listeners.iterator();
    new Thread(){
        @Override
        public void run() {
            while (it.hasNext()) {
                it.next().connectionClosed(c); //FIXME the iterator gets modified 
            }
            };
    }.start();
}}

public class ClientHandlePool implements ClientHandleListener, TaskManagerListener {

        /*...*/
    public synchronized void  removeClientHandle(ClientHandle ch) {
                //here the listeners Vector from the ClientHandle gets modified
        ch.removeListener(this); 
        ch.removeListener(currentListener);
        clientHandles.remove(ch);
    }

    @Override
    public void connectionClosed(ClientHandle ch) {
        removeClientHandle(ch);
    }
}
Was it helpful?

Solution

As far as I know there's no way to retroactively add that ability to any default Collection implementation (Iterable in fact).

But there are implementations that support that kind of behaviour by having well-defined responses to concurrent modification while iterating.

One example is the CopyOnWriteList.

OTHER TIPS

In case of listeners, you might think about using java.util.concurrent.CopyOnWriteArrayList as you typically have way more reads than writes.

have a look at java.util.concurrent package you will find everything you need.

A lazy way to create a fast, fail-safe iterator: take a copy of the list as an array while locked, and foreach() over the array while unlocked... Can be done with any type of List

private void fireConnectionClosed() {
   final ClientHandle c = this;

   final ClientHandleListener[] listenersArr;
   synchronized(this) {
       listenersArr=listeners.toArray(new ClientHandleListener[0]);
   }
   new Thread(){
       @Override
       public void run() {
          for(ClientHandleListener listener : listenersArr )
              listener.connectionClosed(c);
          }
       };
   }.start();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top