Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java thread hanging when trying to interrupt and join main

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.

like image 728
DavidH Avatar asked May 20 '26 17:05

DavidH


2 Answers

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.

like image 162
Jan Wrobel Avatar answered May 22 '26 06:05

Jan Wrobel


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.

like image 20
Matt Avatar answered May 22 '26 07:05

Matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!