Thursday, January 28, 2010

Interrupting Thread Execution

In one of my programming classes, we had to write a multi-threaded chat server that could accept an arbitrary number of clients and transmit messages from one to another. We knew little about concurrency at the time, so we didn't know how to stop a thread from executing. Because we were young and aspiring students that were motivated to get a project done by a certain deadline, we went where we always go when looking for an answer... Google (and the professor)! This is basically what we found from many different sites, forums, and blog posts (I think my professor agreed/told us to do it this way too):

http://www.roseindia.net/javatutorials/shutting_down_threads_cleanly.shtml

While this will work, this is not the proper or best way to stop a thread and can cause problems with responsiveness, liveness, deadlocks, etc as we will see in later posts. So here is the general idea of the bad example:
package org.tiki.threadexamples;


public class BadThreadStopExample extends Thread {

private boolean continueRunning = true;

public void run() {

while ( continueRunning ) {

// Do stuff
System.out.println( "Bad thread is doing its thing." );
}
}

public void cancel() {

continueRunning = false;
}

public static void main( String[] args ) {

BadThreadStopExample thread = new BadThreadStopExample();
thread.start();

// Do stuff

thread.cancel();
}
}
So what is the correct way of handling these things? I'm glad you asked. I've recently been reading the book Java Concurrency in Practice by Brian Goetz and I highly recommend it. After reading a few chapters, it boggles my mind as to why there are so many examples on the internet that follow the above paradigm. I am guilty of writing similar code in most of my multithreaded programs, so if you've done this, you're not alone. I have been enlightened on how this should be written (thank you Brian Goetz)... the thread interruption methods!

  • public void interrupt()

  • public boolean isInterrupted()

  • public static boolean interrupted()

Using these methods, we can change the above code into this:
package org.tiki.threadexamples;


public class GoodThreadStopExample extends Thread {

public void run() {

while ( !Thread.currentThread().isInterrupted() ) {

// Do stuff
System.out.println( "Good thread is doing its thing." );
}
}

public void cancel() {

interrupt();
}

public static void main( String[] args ) {

GoodThreadStopExample thread = new GoodThreadStopExample();
thread.start();

// Do stuff

thread.cancel();
}
}
So this code now sends an interrupt message to the thread, and the while loop now checks that message instead of defining your own variable. However, if blocking functions are in the loop, such as serverSocket.accept() or in.readLine(), the thread may not behave as you think it would. Interrupt methods don't always cause blocking functions to stop what they are doing. How to handle these cases is a bit different and what you do to handle them can depend on the situation and the requirements of the program... So that is for another post.

No comments:

Post a Comment