Thread-safe CopyOnWriteArrayList reverse iteration

Consider the following code snippet:

private List<Listener<E>> listenerList = new CopyOnWriteArrayList<Listener<E>>();

public void addListener(Listener<E> listener) {
    if (listener != null) {
        listenerList.add(listener);
    }
}

public void removeListener(Listener<E> listener) {
    if (listener != null) {
        listenerList.remove(listener);
    }
}

protected final void fireChangedForward(Event<E> event) {
    for (Listener<E> listener : listenerList) {
        listener.changed(event);
    }
}

protected final void fireChangedReversed(Event<E> event) {
    final ListIterator<Listener<E>> li = listenerList.listIterator(listenerList.size());
    while (li.hasPrevious()) {
        li.previous().changed(event);
    }
}

There is a list of listeners that you can change and repeat. I think iteration ahead (see #fireChangedForward Method) should be safe. Question: is reverse iteration (see #fireChangedReversed method) also safe in a multi-threaded environment? I doubt that since there are two calls: #size and #listIterator. If it is not thread safe, then what is the most efficient way to implement #fireChangedReversed in the following circumstances:

  • bypass optimization
  • avoid using locks if possible
  • avoid using javax.swing.event.EventListenerList
  • , .
+4
3

, listenerList.listIterator(listenerList.size()) , , : size() listIterator(), , IndexOutOfBoundsException.

- CopyOnWriteArrayList :

    CopyOnWriteArrayList<Listener<E>> listenerList = ... ;
    @SuppressWarnings("unchecked")
    List<Listener<E>> copy = (List<Listener<E>>)listenerList.clone();
    ListIterator<Listener<E>> li = copy.listIterator(copy.size());

. , . ,

. ( .)

( , : ", , !" , , , , .)

, clone(), .

JDK-6821196 JDK-8149509. concurrency -interest.

+4

- #toArray .

+1

ListIterator "fast-forward" :

final ListIterator<Listener<E>> li = listenerList.listIterator();
if (li.hasNext()) {
    do{
    li.next();
    } while (li.hasNext());
}
while (li.hasPrevious()) {
        li.previous().changed(event);
    }

EDIT . I switched the fancy exception handling from my previous answer to the do / while loop, which places the cursor ListIteratorafter the last element to be ready for the next previous.

RE-EDIT As pointed out by @MikeFHay, the do / while loop on the iterator will throw NoSuchElementExceptioninto an empty list. To prevent this from happening, I wrapped the do / while loop with if (li.hasNext()).

+1
source

Source: https://habr.com/ru/post/1668829/


All Articles