Skip to content

Instantly share code, notes, and snippets.

@amanteaux
Created April 25, 2020 09:14
Show Gist options
  • Save amanteaux/675491e8509f718040f18614bf51c573 to your computer and use it in GitHub Desktop.
Save amanteaux/675491e8509f718040f18614bf51c573 to your computer and use it in GitHub Desktop.
Java IO operations cannot be stopped unless they are specifically written to do so
Thread will maybe be stopped in 5 seconds... 1587805793341
Message from remote at 1587805796619: Hello from netcat
Is thread dead yet? 1587805798342
Message from remote at 1587805811746: I am still alive :)
Message from remote at 1587805818037: OK see you!
End of thread process: 1587805818939
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
public class JavaIoOperationThreadInterrupt {
public static void main(String[] args) throws IOException, InterruptedException {
Thread thread = new Thread(() -> {
try {
Socket s = new Socket(InetAddress.getByName("192.168.1.27"), 1234);
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while((t = br.readLine()) != null) {
System.out.println("Message from remote at "+System.currentTimeMillis()+": " + t);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("End of thread process: " + System.currentTimeMillis());
}
});
thread.start();
System.out.println("Thread will maybe be stopped in 5 seconds... " + System.currentTimeMillis());
Thread.sleep(5000L);
thread.interrupt();
System.out.println("Is thread dead yet? " + System.currentTimeMillis());
}
}
pi@raspberrypi:~ $ nc -l 1234
Hello from netcat
I am still alive :)
OK see you!
^C
pi@raspberrypi:~ $
@danielcuadra
Copy link

You are right @amanteaux! Java socket does not hear for interruption.

However, this one issue could be worked-around like this (not always a choice):

        Thread thread = new Thread() {
            Socket s = null;

            @Override
            public void run() {
                try {
                    s = new Socket();
                    s.connect(new InetSocketAddress(InetAddress.getByName("192.168.1.27"), 1234));
                    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    String t;
                    while((t = br.readLine()) != null) {
                        System.out.println("Message from remote at "+System.currentTimeMillis()+": " + t);
                    }
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("End of thread process: " + System.currentTimeMillis());
                }
            }

            @Override
            public void interrupt() {
                if (s != null) {
                    try {
                        s.shutdownInput();
                    } catch(final Exception ex) {
                        ex.printStackTrace();
                    }
                    try {
                        s.close();
                    } catch(final Exception ex) {
                        ex.printStackTrace();
                    }
                }

                super.interrupt();
            }
        };

@amanteaux
Copy link
Author

Hi @danielcuadra, thank you for your response!
Though your solution seems to be perfectly working, in general if you need interruptible IO, the easiest solution is to switch to Java NIO implementations.

Here is a quick and dirty adaptation of the initial non-interruptible IO example to make it interruptible using java.nio.channels.SocketChannel:

Thread thread = new Thread(() -> {
	try {
		SocketChannel s = SocketChannel.open();
		s.connect(new InetSocketAddress("192.168.1.27", 1234));
		BufferedReader br = new BufferedReader(new InputStreamReader(s.socket().getInputStream()));
		String t;
		while((t = br.readLine()) != null) {
			System.out.println("Message from remote at "+System.currentTimeMillis()+": " + t);
		}
		br.close();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		System.out.println("End of thread process: " + System.currentTimeMillis());
	}
});

With this implementation, I have now this output:

Thread will maybe be stopped in 5 seconds... 1588930581482
Message from remote at 1588930584618: Hello from netcat
Is thread dead yet? 1588930586484
java.nio.channels.ClosedByInterruptException
	at java.base/java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:199)
	at java.base/sun.nio.ch.SocketChannelImpl.endRead(SocketChannelImpl.java:334)
	at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:361)
	at java.base/sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:203)
	at java.base/sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103)
	at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
	at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
	at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
	at java.base/java.io.InputStreamReader.read(InputStreamReader.java:185)
	at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
	at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
	at test.JavaIoOperationThreadInterrupt.lambda$0(JavaIoOperationThreadInterrupt.java:18)
	at java.base/java.lang.Thread.run(Thread.java:834)
End of thread process: 1588930586489

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment