How to terminate a thread blocking on socket IO operation instantly?
Asked Answered
K

2

80

In the context of Java, I create a new thread to read network input when open a GUI window, and when i close the window, i want to release the socket resource and terminate the thread immediately. Now i am using setSoTimeout method, but i don't want to wait the timeout exception. Could anybody give some suggestion? Thanks!

Katlin answered 13/12, 2010 at 2:19 Comment(0)
N
65

There are (potentially) three ways to do this:

  • Calling Socket.close() on the socket will close the associated InputStream and OutputStream objects, and cause any threads blocked in Socket or (associated) stream operations to be unblocked. According to the javadoc, operations on the socket itself will throw a SocketException.

  • Calling Thread.interrupt() will (under some circumstances that are not specified) interrupt a blocking I/O operation, causing it to throw an InterruptedIOException.

    Note the caveat. Apparently the "interrupt()" approach doesn't work on "most" modern Java platforms. (If someone else had the time and inclination, they could possible investigate the circumstances in which this approach works. However, the mere fact that the behavior is platform specific should be sufficient to say that you should only use it if you only need your application to work on a specific platform. At which point you can easily "try it" for yourself.)

  • A possible third way to do this is to call Socket.shutdownInput() and/or Socket.shutdownOutput(). The javadocs don't say explicitly what happens with read and/or write operations that are currently blocked, but it is not unreasonable to think that they will unblock and throw an exception. However, when the javadoc doesn't say what happens, the behavior should be assumed to be platform specific.

Nonunionism answered 13/12, 2010 at 5:27 Comment(4)
pretty sure most jvm implementations do not support interruptible io operations. i think maybe the sun solaris jvm supported it at one point.Twill
As an addendum to this, because a lot of Java programmers these days are actually working on Android, it should be noted that some versions of Android have a bug in Socket.close () that stops this technique working. Calling Socket.shutdownInput() beforehand does work, however.Tuner
On MacOsx 10.13.3 java version "1.8.0_161" interrupting a thread gives me a IOException.Headed
for me shutdownInput() does not unblock an existing read(), more specific a readObject()Cloak
B
20

I know this question is old but as nobody seems to have solved the "mystery" of Thread.interrupt() on "modern platforms" I did some research.

This is tested on Java 8 on Windows7 (64-bit) (but it will possibly be true for other platforms as well).

Calling Thread.interrupt() does not throw an InterruptedIOException What happens is that the InputStream.read() method returns with -1 and Thread.interrupted()-flag is set.

So the following could be considered a 'corrected' read() throwing 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;
}
Believe answered 18/4, 2016 at 15:37 Comment(2)
This answer deserves more up votes because Java's behavior when interrupted during Input/Output stream operations is not what many people expect.Ibex
This method works only if the InputStream provides data that can be read. Otherwise the code will be blocked by in.read(...) and the check if the thread has been interrupted will never be executed.Heinie

© 2022 - 2024 — McMap. All rights reserved.