Billie
Erfahrenes Mitglied
Hellas!
Also, ich möchte nur sichergehen dass ich richtig gehe.
Angenommen wir registrieren einen Listener auf einem Subject, als Beispiel einen Wecker:
und eine schlafende Person als Listener die nach einer Sekunde vom Wecker geweckt wird:
Also der AlarmClock-Thread ist der selbe Thread der die schlafende Person weckt (wakeUp()) und gleichzeitig der Thread, der den Listener wieder entfernt.
Wird jetzt die Klasse SleepingPerson über die main-Methode gestartet, bekommen wir eine ConcurrentModificationException obwohl alle Zugriffe auf die Listener in der AlarmClock synchronisiert erfolgen.
Ist es jetzt richtig dass das Problem die foreach-Schleife in AlarmClock.notifyListeners() ist? Um genau zu sein, ist das Problem der Iterator der intern von der foreach-Schleife verwendet wird und durch ein removeWakeUpListener natürlich nicht aktualisiert wird?
Ist somit folgende (funktionierende) Variante eine gute Lösung:
Ich nehme an der Zugriff auf die Liste muss trotzdem immer synchronisiert erfolgen, ansonsten gibt es irgendwann eine ArrayIndexOutOfBoundsException?
Beste Grüße,
Billie
Also, ich möchte nur sichergehen dass ich richtig gehe.
Angenommen wir registrieren einen Listener auf einem Subject, als Beispiel einen Wecker:
Java:
public class AlarmClock extends Thread {
private List<IWakeUpListener> listeners = null;
private long sleep = 0L;
public AlarmClock(final long sleep) {
this.sleep = sleep;
listeners = new ArrayList<IWakeUpListener>();
}
private void notifyListeners() {
synchronized (listeners) {
for (IWakeUpListener listener : listeners) {
listener.wakeUp();
}
}
}
public void addWakeUpListener(IWakeUpListener e) {
synchronized (listeners) {
listeners.add(e);
}
}
public void removeWakeUpListener(IWakeUpListener e) {
synchronized (listeners) {
listeners.remove(e);
}
}
@Override
public void run() {
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
notifyListeners();
}
}
und eine schlafende Person als Listener die nach einer Sekunde vom Wecker geweckt wird:
Java:
public class SleepingPerson implements IWakeUpListener {
private AlarmClock clock = null;
private SleepingPerson() {
clock = new AlarmClock(1000L);
clock.start();
clock.addWakeUpListener(this);
}
@Override
public void wakeUp() {
System.out.println("I'm awake");
clock.removeWakeUpListener(this);
}
public final static void main(String args[]) {
SleepingPerson person = new SleepingPerson();
}
}
Also der AlarmClock-Thread ist der selbe Thread der die schlafende Person weckt (wakeUp()) und gleichzeitig der Thread, der den Listener wieder entfernt.
Wird jetzt die Klasse SleepingPerson über die main-Methode gestartet, bekommen wir eine ConcurrentModificationException obwohl alle Zugriffe auf die Listener in der AlarmClock synchronisiert erfolgen.
Ist es jetzt richtig dass das Problem die foreach-Schleife in AlarmClock.notifyListeners() ist? Um genau zu sein, ist das Problem der Iterator der intern von der foreach-Schleife verwendet wird und durch ein removeWakeUpListener natürlich nicht aktualisiert wird?
Ist somit folgende (funktionierende) Variante eine gute Lösung:
Java:
private void notifyListeners() {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
IWakeUpListener listener = listeners.get(i);
listener.wakeUp();
}
}
}
Ich nehme an der Zugriff auf die Liste muss trotzdem immer synchronisiert erfolgen, ansonsten gibt es irgendwann eine ArrayIndexOutOfBoundsException?
Beste Grüße,
Billie
Zuletzt bearbeitet von einem Moderator: