So I've been struggling with this problem for a whole day now, and having consulted some threading tutorials and examples am still failing to achieve my desired result.
I have a Thread whose only job is to poll a LinkedBlockingQueue of Strings and then use a PrintWriter to deliver the Strings over a socket to a client. That functionality is working fine, but I am now trying to enhance it by allowing it to gracefully fail in the event of a connection interruption and restart. In order to accomplish this, I am calling interrupt on the thread, and then join, with the end goal of recreating the Thread object to start over. Unfortunately the Thread hangs on the call of join which must mean the Thread never actually manages to die, but I am totally bewildered as to why this might be. Relevant code below.
try {
resultSetStreamer.interrupt();
resultSetStreamer.join();
logger.info("Streamer finished.");
} catch (InterruptedException e) {}
Actual thread code;
class ResultSetStreamer implements Runnable {
GZIPOutputStream gzos = null;
Socket clientSocket = null;
@Override
public void run() {
try {
logger.debug("Thread started.");
// Blocks and waits for an external connection.
clientSocket = serverSocket.accept();
// Creates a compression stream using best possible compression
// to the external connection.
gzos = new GZIPOutputStream(clientSocket.getOutputStream()) {
{
def.setLevel(compression);
}
};
PrintWriter toClient = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(gzos), bufferSize), false);
while (true) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
if (moreRowsToReceive || !dataBuffer.isEmpty()) {
// Synchronisation point.
String row = dataBuffer.poll(pollTime,
TimeUnit.MILLISECONDS);
if (row != null) {
toClient.println(row);
logger.trace("Current row: " + ++currentCount + ".");
}
} else {
toClient.flush();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
gzos.finish();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
logger.debug("Thread finished.");
}
}
Main place to look at is the while(true) loop, which should always loop around and check if the Thread has been interrupted, in which case it throws the exception which is caught at the bottom in order to allow the Thread to die. I don't think the PrintWriter should be blocking the execution of code. Any help would be much appreciated.
JVM does not enforce interruption to terminate the thread. You need to make sure that all blocking calls that your code invokes support interruption.
For example, if client is not receiving data, output buffer will fill up and toClient.println() will block, but this call does not support interruptions so calling .interrupt() won't terminate it.
I would advice to add more debug logs to determine where exactly the code blocks.
On the machine you're running, try starting up jconsole and attaching to your running program. Under the "threads" tab, you should be able to click on each thread and see what it's currently doing. This should give you an indication of what statement on your Runnable object has not yet completed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With