Threads and Multithreading – Part 4

Threads - images of multicoloured threads

This is part 4 of this series. If you missed any of the last three, you can find them here:

In this post, we’ll look at how to terminate a thread gracefully and interrupting threads.

Terminating Threads

We’ve already seen an example of the run() method in the previous post:

@Override
public void run() {
    while (true) {
        statements;
    }
}

We’ve seen that there is no way to stop this thread other than to set it to be a daemon thread, which will be stopped when the JVM closes.

But what happens if we have a long-running application, and the JVM doesn’t close?

We can call the deprecated stop() method of the Thread class. But this has all sorts of serious ramifications when we’re dealing with synchronized methods holding monitors, and can lead to data integrity problems. We’ll discuss these issues in detail in later posts.

We should rather have a boolean flag in the run() method to check whether the thread should keep running, as follows:

@Override
public void run() {
    while (moreWorkToDo) {
        statements;
    }
}

By setting the boolean flag to false we can end the loop and allow the thread to terminate gracefully .

Interrupting Threads

A thread should not work continuously in its run() method. It should sleep() or wait() occasionally to allow other threads an opportunity to run. The sleep(), wait() and join() methods are blocking methods. When a thread is blocked, however, it cannot check the boolean flag to see whether it should end.

The interrupt() method can be called to interrupt these blocking methods. The thread needs to call the interrupted() method to check whether it has been interrupted. When the interrupt() method is called on a thread that is blocked, the blocking method is terminated by an InterruptedException. The InterruptedException can then be used as a request for termination.

The following example shows how the InterruptedException and interrupted() method can be used in the run() method:

public void run() {
    try {
        while (!interrupted() && moreWorkToDo) {
            statements; // with one or more blocking methods
        }
    }
    catch (InterruptedException e) {
        // thread was interrupted during a blocking method
        // we can generally safely ignore this
    }
    finally {
        // clean up code if necessary
    }
    // thread can exit and terminate
} // end of run()

Example

Let’s take the example code from last post, and strip some lines from it:

public class InterruptedThreadTest {

    public static void main(String args[]) {

        Thread task = new Thread (
            // anonymous inner class
            new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println("Hello " + threadName);
                    while (true) {
                        System.out.print('.');
                    }
                }
            }
        );

        // main thread prints its default name
        System.out.println("Hello " + Thread.currentThread().getName());

        // background task runs in parallel as a separate thread
        task.setDaemon(true);
        task.start();

        System.out.println("Done!");

    } // end of main

} // end of class

If the background thread task is a daemon thread, it ends when the main thread ends. If we change the task.setDaemon(true) call to false, the background thread never ends, and prints forever.

Let’s try to interrupt the task before the "Done!" line by adding an interrupt() call as follows:

task.interrupt();
System.out.println("Done!");

Nothing happens! The background thread still spins forever in its loop! What went wrong?

We all know someone who talks incessantly, and no matter how much we try to interrupt them, they just carry on talking. This background task is like that: it doesn’t listen to anyone trying to get a word in.

Let’s now modify the code to include the interrupted() check. We’ll change the while(true) line to while (!Thread.interrupted()). We’ll also put the main thread to sleep for a while so that the background task has a bit of time to do its work:

public class InterruptedThreadTest {

    public static void main(String args[]) throws Exception {

        Thread task = new Thread (
            // anonymous inner class
            new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    System.out.println("Hello " + threadName);
                    while (!Thread.interrupted()) {
                        System.out.print('.');
                    }
                }
            }
        );

        // main thread prints its default name
        System.out.println("Hello " + Thread.currentThread().getName());

        // background task runs in parallel as a separate thread
        task.setDaemon(false);
        task.start();

        // main thread sleeps for 10 milliseconds to give task time to run
        // I've cheated by not catching InterruptedException here, but
        // have declared main() to throw it to keep the code clear.
        Thread.sleep(10); 

        // interrupting the background task
        task.interrupt();
        System.out.println("Done!");

    } // end of main

} // end of class

Now the background task runs as before, but checks in the loop condition whether it’s been interrupted. If it has been interrupted, it ends gracefully.

We didn’t use the moreWorkToDo flag here as recommended earlier, i.e:

while (!interrupted() && moreWorkToDo)

but it’s the work of a moment for a sterling programmer to include it and test it.

Conclusion

In the next post we’ll look at the use of the synchronized keyword, the thread monitor model, and the wait() and notify() methods of the Object class.

Please share your comments.

Until then, stay safe and keep coding!

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.