public final class ClientGateway {
private static ClientGateway instance;
private static List<NetworkClientListener> listeners = Collections.synchronizedList(new ArrayList<NetworkClientListener>());
private static final Object listenersMutex = new Object();
protected EventHandler eventHandler;
private ClientGateway() {
eventHandler = new EventHandler();
}
public static synchronized ClientGateway getInstance() {
if (instance == null)
instance = new ClientGateway();
return instance;
}
public void addNetworkListener(NetworkClientListener listener) {
synchronized (listenersMutex) {
listeners.add(listener);
}
}
class EventHandler {
public void onLogin(final boolean isAdviceGiver) {
new Thread() {
public void run() {
synchronized (listenersMutex) {
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
}
}
}.start();
}
}
}
Этот код генерирует исключение ConcurrentModificationException. Но я подумал, что если они оба синхронизируются на listenersMutex, то они должны выполняться последовательно?Весь код в функциях, которые работают со списком слушателей, работает в синхронизированных блоках, которые синхронизируются в Mutex.Единственный код, который изменяет список, это addNetworkListener (...) и removeNetworkListener (...), но в данный момент никогда не вызывается removeNetworkListener.
То, что происходит с ошибкой, заключается в том, что NetworkClientListener по-прежнемудобавляется, пока функция / поток onLogin выполняет итерацию слушателей.
Спасибо за понимание!
EDIT: NetworkClientListener является интерфейсом и оставляет реализацию "onLogin""до кодера, реализующего функцию, но их реализация функции не имеет доступа к списку слушателей.
Кроме того, я просто полностью перепроверил, и нет никакого изменения списка вне addNetworkListener ()и функции removeNetworkListener (), остальные функции только повторяют список.Изменение кода с:
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
На:
for(int i = 0; i < listeners.size(); i++)
nl.onLogin(isAdviceGiver);
Появляется для решения проблемы параллелизма, , но я уже знал это и хотел бы знать, что вызывает его впервое место.
Еще раз спасибо за вашу постоянную помощь!
Исключение: Исключение в потоке "Thread-5" java.util.ConcurrentModificationException в java.util.ArrayList $ Itr.checkForComodification $(ArrayList.java:782) на java.util.ArrayList $ Itr.next (ArrayList.java:754) на chapchat.client.networkcommunication.ClientGateway $ EventHandler $ 5.run (ClientGateway.java:283)
РЕДАКТИРОВАТЬ Хорошо, я чувствую себя немного глупым.Но спасибо за вашу помощь!В частности, MJB & jprete!
Ответ: Кто-то реализовал onLogin (), добавив новый слушатель к шлюзу.Поэтому (поскольку синхронизация java основана на потоках и является реентерабельной, поэтому поток может не блокироваться сам по себе), когда мы вызывали onLogin () в его реализации, мы перебирали слушателей и в процессе этого добавлялиновый слушатель.
Решение: предложение MJB использовать CopyOnWriteArrayList вместо синхронизированных списков