Mein Java NIO Selector wird mit implementiert Wählen Sie () , so dass es blockiert, bis einer dieser Fälle auftritt:
Daraus habe ich einige Annahmen über den Fall gemacht, dass select()
0 zurückgibt:
ResultSet
selectedKeys()
aufrufen und kann mit der nächsten Schleifeniteration fortfahren, bei der select()
erneut aufgerufen wird Ich bin jedoch auf Situationen gestoßen, in denen select()
0 zurückgegeben hat, obwohl ein fertiger Kanal vorhanden ist. selectedKeys()
gibt eine Set
mit 1 SelectionKey
wie erwartet zurück.
Selbst mehrere Aufrufe von select()
würden immer 0 zurückgeben, bis der Kanal verarbeitet wurde und SelectionKey
entfernt wurde. Diese Situation endet im Grunde in einer Endlosschleife, da select()
nicht blockiert, sondern immer sofort 0 zurückgibt.
Vereinfachter Code:
%Vor% Warum gibt select()
0 zurück, obwohl ein fertiger Kanal vorhanden ist?
Was ist der vorgeschlagene Weg, damit umzugehen?
BEARBEITEN:
Dies ändern:
%Vor%zu diesem
%Vor% hat das Problem gelöst. In einigen Fällen würde der Code continue
der for
Schleife vor remove()
des Schlüssels sein.
EDIT 2:
Ich habe gerade erst erfahren, dass meine foreach -Schleife über dem ausgewählten Schlüsselsatz schlecht ist. foreach verwendet den Iterator des Sets. Wenn Sie eine Sammlung direkt (nicht über die Methoden des Iterators) ändern, während Sie darüber iterieren, kann dies zu einem "willkürlichen, nicht deterministischen" Verhalten führen.
Der ausgewählte Schlüsselsatz kann einen Fail-Fast Iterator bereitstellen. Fail-fast Iteratoren erkennen solche Änderungen und werfen eine ConcurrentModificationException ein bei der nächsten Iteration. Wenn also die Menge in einer foreach geändert wird, besteht entweder das Risiko eines unbestimmten Verhaltens oder es können Ausnahmen auftreten - abhängig von der Iterator-Implementierung.
Lösung: Verwenden Sie nicht foreach . Verwenden Sie den Iterator und entfernen Sie den Schlüssel über iterator.remove ( ) .
%Vor% select()
gibt die Anzahl der Schlüssel zurück, die geändert haben. Wenn also ein Schlüssel bereits vor dem Aufruf select()
bereit war, könnte er 0 zurückgeben, aber selectedKeys
könnte nicht leer sein.
Wie Sie bereits bemerkt haben, liegt dies daran, dass Sie den ausgewählten Schlüssel nicht aus dem ausgewählten Set entfernt haben.
Da wir normalerweise alle ausgewählten Schlüssel nach der Verarbeitung des Sets entfernen möchten, können Sie einfach clear()
für das Set nach Ihrer Schleife aufrufen, was eine beliebige oder jede Art von Schleife sein kann :
Auf diese Weise können Sie jede Art von Schleife verwenden ("regulär" for
oder Iteratoren) und sicherstellen, dass alle ready-keys entfernt werden, egal was Sie innerhalb der for
tun (einschließlich der problematischen% Code%). Je nachdem, was die continue
intern tut, ist es möglicherweise effizienter, iterator.remove()
einmal anstelle von mehreren clear()
aufzurufen (obwohl das wahrscheinlich eine Mikrooptimierung wäre).