Java NIO Selector () gibt 0 zurück, obwohl die Kanäle bereit sind

9

Mein Java NIO Selector wird mit implementiert Wählen Sie () , so dass es blockiert, bis einer dieser Fälle auftritt:

  1. ein registrierter Kanal ist bereit
  2. es ist wakeup () 'ed
  3. Der Thread ist unterbrochen

Daraus habe ich einige Annahmen über den Fall gemacht, dass select() 0 zurückgibt:

  • es muss Grund 2 oder 3 gewesen sein.
  • selectedKeys () sollte einen zurückgeben leer ResultSet
  • Ich muss nicht 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%     
riha 30.03.2012, 09:05
quelle

2 Antworten

8

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.

    
benmmurphy 30.03.2012, 09:14
quelle
1

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 :

%Vor%

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).

    
Matthieu 16.02.2015 01:20
quelle

Tags und Links