Wie kann ich eine Thread-Blockierung beim Socket-E / A-Betrieb sofort beenden?

73

Im Kontext von Java erstelle ich einen neuen Thread zum Lesen von Netzwerkeingaben, wenn ein GUI-Fenster geöffnet wird. Wenn ich das Fenster schließe, möchte ich die Socket-Ressource freigeben und den Thread sofort beenden. Jetzt verwende ich die setSoTimeout-Methode, aber ich möchte nicht auf die Timeout-Ausnahme warten. Könnte jemand einen Vorschlag machen? Vielen Dank!

Dingxin Xu
quelle
11
Ich verstehe nicht, warum das eine -1 hat?!? Ich denke, die Frage war ganz klar und vor Ort.
Max Kielland

Antworten:

60

Es gibt (möglicherweise) drei Möglichkeiten, dies zu tun:

  • Durch Aufrufen Socket.close()des Sockets werden die zugehörigen InputStreamund OutputStreamObjekte geschlossen und alle in Socket- oder (zugeordneten) Stream-Vorgängen blockierten Threads werden entsperrt. Laut Javadoc werfen Operationen an der Steckdose selbst a SocketException.

  • Durch das Aufrufen Thread.interrupt()wird (unter bestimmten Umständen, die nicht angegeben sind) eine blockierende E / A-Operation unterbrochen, wodurch eine ausgelöst wird InterruptedIOException.

    Beachten Sie die Einschränkung. Anscheinend funktioniert der "Interrupt ()" - Ansatz auf den "meisten" modernen Java-Plattformen nicht. (Wenn jemand anderes die Zeit und die Neigung hätte, könnte er möglicherweise die Umstände untersuchen, unter denen dieser Ansatz funktioniert. Die bloße Tatsache, dass das Verhalten plattformspezifisch ist, sollte jedoch ausreichen, um zu sagen, dass Sie es nur verwenden sollten, wenn Sie nur Ihre Anwendung benötigen an einer bestimmten Plattform zu arbeiten. An diesem Punkt können Sie es einfach selbst "ausprobieren".)

  • Ein möglicher dritter Weg, dies zu tun, ist anzurufen Socket.shutdownInput()und / oder Socket.shutdownOutput(). Die Javadocs sagen nicht explizit, was mit Lese- und / oder Schreibvorgängen passiert, die derzeit blockiert sind, aber es ist nicht unangemessen zu glauben, dass sie die Blockierung aufheben und auslösen. Wenn der Javadoc jedoch nicht sagt, was passiert, sollte davon ausgegangen werden, dass das Verhalten plattformspezifisch ist.

Stephen C.
quelle
2
Bitte unter welchen Umständen wird thread.interrupt () einen blockierenden E / A-Vorgang unterbrechen?
Dingxin Xu
3
Xu DXn - es ist nicht dokumentiert. Einige Streams implementieren dies, andere nicht. Lesen Sie den OpenJDK-Quellcode, um die wichtigsten Details zu erfahren. Der Punkt, den ich versuche, ist, dass es funktionieren kann oder nicht.
Stephen C
1
ziemlich sicher , dass die meisten Jvm Implementierungen nicht unterstützen unterbrechbare io - Operationen. Ich denke, vielleicht hat die Sonne Solaris JVM es an einem Punkt unterstützt.
Jtahlborn
8
Als Ergänzung dazu sollte beachtet werden, dass einige Android-Versionen einen Fehler in Socket.close () haben, der diese Technik stoppt, da viele Java-Programmierer heutzutage tatsächlich mit Android arbeiten. Das vorherige Aufrufen von Socket.shutdownInput () funktioniert jedoch.
Jules
Können Sie klären, ob die vorhandene Blockierungsoperation SocketException auslöst oder ob nur neue Operationen auf dem Socket SocketException auslösen?
user239558
18

Ich weiß, dass diese Frage alt ist, aber da niemand das "Geheimnis" Thread.interrupt()auf "modernen Plattformen" gelöst zu haben scheint, habe ich einige Nachforschungen angestellt.

Dies wird unter Java 8 unter Windows 7 (64-Bit) getestet (dies gilt jedoch möglicherweise auch für andere Plattformen).

Der Aufruf Thread.interrupt()ist nicht ein Wurf InterruptedIOException Was passiert , ist , dass die InputStream.read()Methode zurückgibt , mit -1und Thread.interrupted()-Kennzeichen gesetzt ist.

Folgendes könnte also als "korrigiertes" Lesen von read () angesehen werden InterruptedIOException:

static final int read(Socket socket, byte[] inData) 
    throws SocketTimeoutException, // if setSoTimeout() was set and read timed out
           InterruptedIOException, // if thread interrupted
           IOException             // other erors
{
    InputStream in = socket.getInputStream();

    int readBytes = in.read( inData, 0, inData.length);

    if  ( Thread.interrupted() )
    {
        throw new InterruptedIOException( "Thread interrupted during socket read");
    }

    return readBytes;
}
raudi
quelle
1
Diese Antwort verdient mehr Stimmen, da das Verhalten von Java bei Unterbrechung während der Eingabe- / Ausgabestream-Vorgänge nicht den Erwartungen vieler Menschen entspricht.
Tom N.
8
Diese Methode funktioniert nur, wenn der InputStream Daten bereitstellt, die gelesen werden können. Andernfalls wird der Code von blockiert in.read(...)und die Überprüfung, ob der Thread unterbrochen wurde, wird niemals ausgeführt.
Robert