Chapter 1

Programming Threads

IN THIS CHAPTER

check Examining threads

check Creating threads from the Thread class

check Working with the Runnable interface

check Creating threads that cooperate

check Executing threads

check Making methods cooperate

check Using a lock

check Interrupting threads

Have you ever seen a plate-spinning act, in which a performer spins plates or bowls on top of poles, keeping multiple plates spinning at the same time, running from pole to pole to give each plate a little nudge — just enough to keep it going? The world record is 108 plates kept simultaneously spinning.

In Java, threads are the equivalent of plate spinning. Threads let you divide the work of an application into separate pieces, all of which then run simultaneously. The result is a faster and more efficient program, but along with the increased speed come more difficult programming and debugging.

Truthfully, the subtleties of threaded programming are a topic for computer science majors, but the basics of working with threads aren’t all that difficult to understand. In this chapter, I focus on those basics and leave the advanced techniques for the grad students.

Warning The main application I use to illustrate threading in this chapter simulates the countdown clock for the spacecraft. Working with threads isn’t really rocket science, but threading is used to solve difficult programming problems. You invariably find yourself trying to get two or more separate pieces of code to coordinate their activities, and that’s not as easy as you might think at first guess. As a result, I can’t possibly talk about threading without getting into some challenging mental exercises, so be prepared to spend some mental energy figuring out how it works.

Tip The listings in this chapter, as well as throughout the book, are available at www.dummies.com/go/javaaiofd6e.

Understanding Threads

A thread is a single sequence of executable code within a larger program. All the programs shown so far in this book have used just one thread — the main thread that starts automatically when you run the program — but Java lets you create programs that start additional threads to perform specific tasks.

You’re probably familiar with programs that use threads to perform several tasks at the same time. Here are some common examples:

  • Web browsers can download files while letting you view web pages. When you download a file in a web browser, the browser starts a separate thread to handle the download.
  • Email programs don’t make you wait for all your messages to download before you can read the first message. Instead, these programs use separate threads to display and download messages.
  • Word processors can print long documents in the background while you continue to work. These programs start a separate thread to handle print jobs.
  • Word processors can also check your spelling as you type. Depending on how the word processor is written, it may run the spell check in a separate thread.
  • Game programs commonly use several threads to handle different parts of the game to improve the overall responsiveness of the game.
  • Tip All GUI-based programs use at least two threads — one thread to run the application’s main logic and another thread to monitor mouse and keyboard events. You find out about creating GUI programs in Java in Book 6.

  • Indeed, the Java Virtual Machine itself uses threading for some of its housekeeping chores. The garbage collector, for example, runs as a separate thread so it can constantly monitor the state of the VM’s memory and decide when it needs to create some free memory by removing objects that are no longer being used.

Creating a Thread

Suppose you’re developing software for NASA, and you’re in charge of the program that controls the final 20 seconds of the countdown for a manned spacecraft. Your software has to coordinate several key events that occur when the clock reaches certain points:

  • T minus 16 seconds: Flood launch pad. This event releases 350,000 gallons of water onto the launch pad, which helps protect the spacecraft systems during launch.
  • T minus 6 seconds: Start the main engines. Huge clamps hold the spacecraft in place while the engines build up thrust.
  • T minus 0: Lift off! The clamps are released, and the spacecraft flies into space.

For this program, I don’t actually start any rocket engines or release huge amounts of water. Instead, I just display messages on the console to simulate these events. But I do create four separate threads to make everything work. One thread manages the countdown clock. The other three threads fire off their respective events at T minus 16 seconds (flood the pad), T minus 6 seconds (fire the engines), and T minus 0 (launch).

For the first attempt at this program, I just get the countdown clock up and running. The countdown clock is represented by a class named CountDownClock. All this class does is count down from 20 to 0 at 1-second intervals, displaying messages such as T minus 20 on the console as it counts. This version of the program doesn’t do much of anything, but it does demonstrate how to get a thread going. We’ll start by looking at the Thread class.

Understanding the Thread class

The Thread class lets you create an object that can be run as a thread in a multithreaded Java application. The Thread class has quite a few constructors and methods, but for most applications, you need to use only the ones listed in Table 1-1. (Note that this table is here to give you an overview of the Thread class and to serve as a reference. Don’t worry about the details of each constructor and method just yet. By the end of this chapter, I explain each of the constructors and methods.)

TABLE 1-1 Constructors and Methods of the Thread Class

Constructor

Explanation

Thread()

Creates an instance of the Thread class. This constructor is the basic Thread constructor without parameters.

Thread(String name)

Creates a Thread object and assigns the specified name to the thread.

Thread(Runnable target)

Turns any object that implements an API interface called Runnable into a thread. You see how this more-advanced constructor is used later in this chapter.

Thread(Runnable target, String name)

Creates a thread from any object that implements Runnable and assigns the specified name to the thread.

static int activeCount()

Returns the number of active threads.

static int enumerate(Thread[] t)

Fills the specified array with a copy of each active thread. The return value is the number of threads added to the array.

String getName()

Returns the name of the thread.

int getPriority()

Returns the thread’s priority.

void interrupt()

Interrupts this thread.

boolean isInterrupted()

Checks whether the thread has been interrupted.

void setPriority(int priority)

Sets the thread’s priority.

void setName(String name)

Sets the thread’s name.

static void Sleep

Causes the currently executing thread (int milliseconds) to sleep for the specified number of milliseconds.

void run()

Is called when the thread is started. Place the code that you want the thread to execute inside this method.

void start()

Starts the thread.

static void yield()

Causes the currently executing thread to yield to other threads that are waiting to execute.

Extending the Thread class

The easiest way to create a thread is to write a class that extends the Thread class. Then all you have to do to start a thread is create an instance of your thread class and call its start method.

Listing 1-1 is a version of the CountDownClock class that extends the Thread class.

LISTING 1-1 The CountDownClock Class (Version 1)

public class CountDownClock extends Thread→1

{

public void run()→3

{

for (int t = 20; t >= 0; t--)→5

{

System.out.println("T minus " + t);

try

{

Thread.sleep(1000);→10

}

catch (InterruptedException e)

{}

}

}

}

Here are a few key points to notice in this class:

  • →1 The CountDownClock class extends the Thread class. Thread is defined in the java.lang package, so you don’t have to provide an import statement to use it.
  • →3 The CountDownClock class has a single method, named run. This method is called by Java when the clock thread has been started. All the processing done by the thread must either be in the run method or in some other method called by the run method.
  • →5 The run method includes a for loop that counts down from 20 to 0.
  • →10 The CountDownClock class uses the sleep method to pause for 1 second. Because the sleep method throws Interrupted Exception, a try/catch statement handles this exception. If the exception is caught, it is simply ignored.

Remember At some point in its execution, the run method should either call sleep or yield to give other threads a chance to execute.

Creating and starting a thread

After you define a class that defines a Thread object, you can create and start the thread. Here’s the main class for the first version of the countdown application:

public class CountDownApp

{

public static void main(String[] args)

{

Thread clock = new CountDownClock();

clock.start();

}

}

Here a variable of type Thread is declared, and an instance of the Count DownClock is created and assigned to it. This creates a Thread object, but the thread doesn’t begin executing until you call its start method.

When you run this program, the thread starts counting down in 1-second increments, displaying messages such as the following on the console:

T minus 20

T minus 19

T minus 18

And so on, all the way to zero. So far, so good.

Implementing the Runnable Interface

For the threads that trigger specific countdown events such as flooding the launch pad, starting the events, and lifting off, I create another class called LaunchEvent. This class uses another technique for creating and starting threads — one that requires a few more lines of code but is more flexible.

The problem with creating a class that extends the Thread class is that a class can have one superclass. What if you’d rather have your thread object extend some other class? In that case, you can create a class that implements the Runnable interface rather than extends the Thread class. The Runnable interface marks an object that can be run as a thread. It has only one method, run, that contains the code that’s executed in the thread. (The Thread class itself implements Runnable, which is why the Thread class has a run method.)

Using the Runnable interface

To use the Runnable interface to create and start a thread, you have to do the following:

  1. Create a class that implements Runnable.
  2. Provide a run method in the class you created in Step 1.
  3. Create an instance of the Thread class and pass your Runnable object to its constructor as a parameter.

    A Thread object is created that can run your Runnable class.

  4. Call the Thread object's start method.

    The run method of your Runnable object is called and executes in a separate thread.

The first two of these steps are easy. The trick is in the third and fourth steps, because you can complete them in several ways. Here’s one way, assuming that your Runnable class is named RunnableClass:

RunnableClass rc = new RunnableClass();

Thread t = new Thread(rc);

t.start();

Java programmers like to be as concise as possible, so you often see this code compressed to something more like

Thread t = new Thread(new RunnableClass());

t.start();

or even just this:

new Thread(new RunnableClass()).start();

This single-line version works — provided that you don’t need to access the thread object later in the program.

Creating a class that implements Runnable

To sequence the launch events for the NASA application, I create a Runnable object named LaunchEvent. The constructor for this class accepts two parameters: the countdown time at which the event fires and the message that is displayed when the time arrives. The run method for this class uses Thread.sleep to wait until the desired time arrives. Then it displays the message.

Listing 1-2 shows the code for this class.

LISTING 1-2 The LaunchEvent Class (Version 1)

public class LaunchEvent implements Runnable→1

{

private int start;

private String message;

public LaunchEvent(int start, String message)→6

{

this.start = start;

this.message = message;

}

public void run()

{

try

{

Thread.sleep(20000 - (start * 1000));→16

}

catch (InterruptedException e)

{}

System.out.println(message);→20

}

}

The following paragraphs draw your attention to the listing’s key lines:

  • →1 This class implements the Runnable interface.
  • →6 The constructor accepts two parameters: an integer representing the start time (in seconds) and a string message that’s displayed when the time arrives. The constructor simply stores these parameter values in private fields.
  • →16 In the run method, the Thread.sleep method is called to put the thread to sleep until the desired countdown time arrives. The length of time that the thread should sleep is calculated by the expression 20000 - (start * 1000). The countdown clock starts at 20 seconds, which is 20,000 milliseconds. This expression simply subtracts the number of milliseconds that corresponds to the desired start time from 20,000. Thus, if the desired start time is 6 seconds, the sleep method sleeps for 14,000 milliseconds — that is, 14 seconds.
  • →20 When the thread wakes up, it displays the message passed via its constructor on the console.

Using the CountDownApp class

Now that you’ve seen the code for the LaunchEvent and CountDownClock classes, Listing 1-3 shows the code for a CountDownApp class that uses these classes to launch a spacecraft.

LISTING 1-3 The CountDownApp Class (Version 2)

public class CountDownApp

{

public static void main(String[] args)

{

Thread clock = new CountDownClock();→5

Runnable flood, ignition, liftoff;→7

flood = new LaunchEvent(16, "Flood the pad!");

ignition = new LaunchEvent(6, "Start engines!");

liftoff = new LaunchEvent(0, "Liftoff!");

clock.start();→12

new Thread(flood).start();→14

new Thread(ignition).start();

new Thread(liftoff).start();

}

}

The following paragraphs summarize how this program works:

  • →5 The main method starts by creating an instance of the Count DownClock class and saving it in the clock variable.
  • →7 Next, it creates three LaunchEvent objects to flood the pad at 16 seconds, start the engines at 6 seconds, and lift off at 0 seconds. These objects are assigned to variables of type Runnable named flood, ignition, and liftoff.
  • →12 The clock thread is started. The countdown starts ticking.
  • →14 Finally, the program starts the three LaunchEvent objects as threads. It does this by creating a new instance of the Thread class, passing the LaunchEvent objects as parameters to the Thread constructor, and then calling the start method to start the thread. Note that because this program doesn’t need to do anything with these threads after they’re started, it doesn’t bother creating variables for them.

When you run this program, output similar to the following is displayed on the console:

T minus 20

T minus 19

T minus 18

T minus 17

T minus 16

Flood the pad!

T minus 15

T minus 14

T minus 13

T minus 12

T minus 11

T minus 10

T minus 9

T minus 8

T minus 7

T minus 6

Start engines!

T minus 5

T minus 4

T minus 3

T minus 2

T minus 1

Liftoff!

T minus 0

As you can see, the LaunchEvent messages are interspersed with the CountDownClock messages. Thus, the launch events are triggered at the correct times.

Note that the exact order in which some of the messages appear may vary slightly. For example, "Flood the pad!" might sometimes come before "T minus 16" because of slight variations in the precise timing of these independently operating threads. Later in this chapter, the section “Creating Threads That Work Together” shows you how to avoid such inconsistencies.

Tip You can improve the main method for this class by using an ArrayList to store the Runnable objects. Then you can start all the LaunchEvent threads by using an enhanced for loop. Here’s what the improved code looks like:

public static void main(String[] args)

{

Thread clock = new CountDownClock();

ArrayList<Runnable> events

= new ArrayList<Runnable>();

events.add(new LaunchEvent(16, "Flood the pad!"));

events.add(new LaunchEvent(6, "Start engines!"));

events.add(new LaunchEvent(0, "Liftoff!"));

clock.start();

for (Runnable e : events)

new Thread(e).start();

}

The advantage of this technique is that you don’t need to create a separate variable for each LaunchEvent. (Don’t forget to add an import statement for the java.util.* to gain access to the ArrayList class.)

Creating Threads That Work Together

Unfortunately, the countdown application presented in the preceding section has a major deficiency: The CountDownClock and LaunchEvent threads depend strictly on timing to coordinate their activities. After these threads start, they run independently of one another. As a result, random variations in their timings can cause the thread behaviors to change. If you run the program several times in a row, you’ll discover that sometimes the Start engines! message appears after the T minus 6 message, and sometimes it appears before the T minus 6 message. That might not seem like a big deal to you, but it probably would be disastrous for the astronauts on the spacecraft. What these classes really need is a way to communicate.

Listing 1-4 shows an improved version of the countdown application that incorporates several enhancements. The CountDownClock class in this version adds a new method named getTime that gets the current time in the countdown. Then the LaunchEvent class checks the countdown time every 10 milliseconds and triggers the events only when the countdown clock actually says that it’s time. This version of the application runs consistently.

In addition, you want to enable the LaunchEvent class to monitor the status of the CountDownClock, but you don’t want to couple the LaunchEvent and CountDownClock classes too closely. Suppose that later, you develop a better countdown clock. If the LaunchEvent class knows what class is doing the counting, you have to recompile it if you use a different countdown class.

The solution is to use an interface as a buffer between the classes. This interface defines a method that gets the current status of the clock. Then the CountDownClock class can implement this interface, and the LaunchEvent class can use any object that implements this interface to get the time.

LISTING 1-4 The Coordinated CountDown Application

import java.util.ArrayList;

// version 2.0 of the Countdown application

public class CountDownApp

{

public static void main(String[] args)

{

CountDownClock clock = new CountDownClock(20);→8

ArrayList<Runnable> events =

new ArrayList<Runnable>();→10

events.add(new LaunchEvent(16,→12

"Flood the pad!", clock));

events.add(new LaunchEvent(6,

"Start engines!", clock));

events.add(new LaunchEvent(0,

"Liftoff!", clock));

clock.start();→19

for (Runnable e : events)→21

new Thread(e).start();

}

}

interface TimeMonitor→26

{

int getTime();

}

class CountDownClock extends Thread

implements TimeMonitor→32

{

private int t;→34

public CountDownClock(int start)→36

{

this.t = start;

}

public void run()

{

for (; t >= 0; t--)→43

{

System.out.println("T minus " + t);

try

{

Thread.sleep(1000);

}

catch (InterruptedException e)

{}

}

}

public int getTime()→55

{

return t;

}

}

class LaunchEvent implements Runnable→61

{

private int start;

private String message;

TimeMonitor tm;→65

public LaunchEvent(int start, String message,

TimeMonitor monitor)

{

this.start = start;

this.message = message;

this.tm = monitor;

}

public void run()

{

boolean eventDone = false;

while (!eventDone)

{

try

{

Thread.sleep(10);→82

}

catch (InterruptedException e)

{}

if (tm.getTime() <= start)→86

{

System.out.println(this.message);

eventDone = true;

}

}

}

}

The following paragraphs describe the high points of this version:

  • →8 As you see in line 35, the constructor for the CountDownClock class now accepts a parameter to specify the starting time for the countdown. As a result, this line specifies 20 as the starting time for the CountDownClock object.
  • →10 An ArrayList of LaunchEvent objects is used to store each launch event.
  • →12 The lines that create the LaunchEvent objects pass the CountDownClock object as a parameter to the LaunchEvent constructor. That way the LaunchEvent objects can call the clock’s abort method if necessary.
  • →19 The clock is started!
  • →21 An enhanced for loop starts threads to run the LaunchEvent objects.
  • →26 The TimeMonitor interface defines just one method, named getTime. This method returns an integer that represents the number of seconds left on the countdown timer.
  • →32 The CountDownClock class implements the TimeMonitor interface.
  • →34 A private field named t is used to store the current value of the countdown clock. That way, the current clock value can be accessed by the constructor, the run method, and the getTime method.
  • →36 The constructor for the CountDownClock class accepts the starting time for the countdown as a parameter. Thus, this countdown clock doesn’t have to start at 20 seconds. The value passed via this parameter is saved in the t field.
  • →43 The for loop in the run method tests and decrements the t variable. But because this variable is already initialized, it doesn’t have an initialization expression.
  • →55 The getTime() method simply returns the value of the t variable.
  • →61 This line is the start of the LaunchEvent class.
  • →65 A private field of type TimeMonitor is used to access the countdown clock. A reference to this object is passed to the LaunchEvent class via its constructor. The constructor simply stores that reference in this field.
  • →82 The while loop includes a call to Thread.sleep that sleeps for just 10 milliseconds. Thus, this loop checks the countdown clock every 10 milliseconds to see whether its time has arrived.
  • →86 This statement calls the getTime method of the countdown clock to see whether it’s time to start the event. If so, a message is displayed, and eventDone is set to true to terminate the thread.

Using an Executor

The countdown application in Listings 1-1 through 1-4 uses Java’s original threading mechanisms — tools that were available in the mid-1990s, when Java was in diapers. Since then, Java programmers have longed for newer, more sophisticated threading techniques. The big breakthrough came in 2004, with the release of Java 1.5. The Java API gained a large assortment of classes for fine-grained control of the running of threads. Since then, subsequent releases of Java have added even more classes to give you even better control over how threads execute.

A full discussion of Java threading would require another 850 pages. (How about Java Threading All-in-One For Masochists?) This chapter presents only a small sampling of these Java threading features.

Listings 1-5 through 1-7 repeat the work done by Listings 1-1 through 1-4, but Listings 1-5 through 1-7 use Java 1.5 threading classes.

LISTING 1-5 A New CountDownClock

public class CountDownClockNew implements Runnable

{

int t;

public CountDownClockNew(int t)

{

this.t = t;

}

public void run()

{

System.out.println("T minus " + t);

}

}

LISTING 1-6 A New Event Launcher

public class LaunchEventNew implements Runnable

{

private String message;

public LaunchEventNew(String message)

{

this.message = message;

}

public void run()

{

System.out.println(message);

}

}

LISTING 1-7 A New CountDown Application

import java.util.concurrent.ScheduledThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

class CountDownAppNew

{

public static void main(String[] args)

{

ScheduledThreadPoolExecutor pool =

new ScheduledThreadPoolExecutor(25);

Runnable flood, ignition, liftoff;

flood = new LaunchEventNew("Flood the pad!");

ignition = new LaunchEventNew("Start engines!");

liftoff = new LaunchEventNew("Liftoff!");

for (int t = 20; t >= 0; t--)

pool.schedule(new CountDownClockNew(t),

(long) (20 - t), TimeUnit.SECONDS);

pool.schedule(flood, 3L, TimeUnit.SECONDS);

pool.schedule(ignition, 13L, TimeUnit.SECONDS);

pool.schedule(liftoff, 19L, TimeUnit.SECONDS);

pool.shutdown();

}

}

In the new version of the countdown application, Listing 1-7 does all the busywork. The listing uses the ScheduledThreadPoolExecutor class. The class’s long name tells much of the story:

  • Scheduled: Using this class, you can schedule a run of code for some future time.
  • ThreadPool: This class typically creates several threads (a pool of threads) at the same time. When you want to run some code, you grab an available thread from the pool and use that thread to run your code.
  • Executor: An Executor executes something. No big surprise here!

The loop in Listing 1-7 spawns 20 threads, each with its own initial delay. The fifth loop iteration, for example, calls

pool.schedule(new CountDownClockNew(16),

(long) (20 - 16), TimeUnit.SECONDS);

In the pool.schedule method call, the number (long) (20 - 16) tells Java to wait 4 seconds before scheduling the T minus 16 thread. Each of the T minus threads has a different delay, so each thread runs at the appropriate time. The same is true of the flood, ignition, and liftoff events.

Synchronizing Methods

Whenever you work on a program that uses threads, you have to consider the nasty issue of concurrency. In particular, what if two threads try to access a method of an object at precisely the same time? Unless you program carefully, the result can be disastrous. A method that performs a simple calculation returns inaccurate results. In an online banking application, you might discover that some deposits are credited twice and some withdrawals aren't credited at all. In an online ordering system, one customer’s order might get recorded in a different customer’s account.

The key to handling concurrency issues is recognizing methods that update data and that might be called by more than one thread. After you identify those methods, the solution is simple. You just add the synchronized keyword to the method declaration, like this:

public synchronized void someMethod()…

This code tells Java to place a lock on the object so that no other methods can call any other synchronized methods for the object until this method finishes. In other words, it temporarily disables multithreading for the object. (I discuss locking in the section “Creating a Lock,” later in this chapter.)

The next several listings present some concrete examples. Listing 1-8 creates an instance of the CountDownClock class (the class in Listing 1-1).

LISTING 1-8 Creating Two CountDownClock Threads

import java.util.concurrent.ScheduledThreadPoolExecutor;

public class DoTwoThings

{

ScheduledThreadPoolExecutor pool =

new ScheduledThreadPoolExecutor(2);

CountDownClock clock = new CountDownClock(20);

public static void main(String[] args)

{

new DoTwoThings();

}

DoTwoThings()

{

pool.execute(clock);

pool.execute(clock);

pool.shutdown();

}

}

The resulting output is an unpredictable mishmash of two threads’ outputs, with some of the counts duplicated and others skipped altogether, like this:

T minus 20

T minus 20

T minus 19

T minus 19

T minus 18

T minus 17

T minus 16

T minus 15

T minus 13

T minus 13

T minus 12

T minus 12

T minus 11

T minus 11

T minus 10

T minus 9

T minus 7

T minus 7

T minus 6

T minus 5

T minus 4

T minus 3

T minus 2

T minus 2

T minus 1

T minus 0

The two threads execute their loops simultaneously, so after one thread displays its T minus 20, the other thread displays its own T minus 20. The same thing happens for T minus 19, T minus 18, and so on.

Then Listing 1-9 spawns two threads, each of which runs a copy of the CountDownClock instance’s code.

LISTING 1-9 Creating Two More CountDownClock Threads

import java.util.concurrent.ScheduledThreadPoolExecutor;

public class DoTwoThingsSync

{

ScheduledThreadPoolExecutor pool =

new ScheduledThreadPoolExecutor(2);

CountDownClockSync clock =

new CountDownClockSync(20);

public static void main(String[] args)

{

new DoTwoThingsSync();

}

DoTwoThingsSync()

{

pool.execute(clock);

pool.execute(clock);

pool.shutdown();

}

}

In Listing 1-10, Java’s synchronized keyword ensures that only one thread at a time calls the run method. The resulting output shows one complete execution of the run method followed by another.

LISTING 1-10 Using the synchronized Keyword

class CountDownClockSync extends Thread

{

private int start;

public CountDownClockSync(int start)

{

this.start = start;

}

synchronized public void run()

{

for (int t = start; t >= 0; t--)

{

System.out.println("T minus " + t);

try

{

Thread.sleep(1000);

}

catch (InterruptedException e)

{}

}

}

}

The two threads’ calls to the run method are not interleaved, so the output counts down from 20 to 0 and then counts down a second time from 20 to 0:

T minus 20

T minus 19

T minus 18

And so on, down to

T minus 2

T minus 1

T minus 0

T minus 20

T minus 19

T minus 18

And so on, down to

T minus 2

T minus 1

T minus 0

Warning The tough part is knowing which methods to synchronize. When I said that any method that updates data can be synchronized, I didn’t mean just any method that updates a database. Any method that updates instance variables is at risk — and needs to be synchronized. That’s because when two or more threads run a method at the same time, the threads have a common copy of the method’s instance variables.

Technical stuff Even methods that consist of just one line of code are at risk. Consider this method:

int sequenceNumber = 0;

public int getNextSequenceNumber()

{

return sequenceNumber++;

}

You’d think that because this method has just one statement, some other thread could not interrupt it in the middle. Alas, that’s not the case. This method must get the value of the sequenceNumber field, add 1 to it, save the updated value back to the sequenceNumber field, and return the value. In fact, this single Java statement compiles to 11 bytecode instructions. If the thread is preempted between any of those bytecodes by another thread calling the same method, the serial numbers get munged.

For safety’s sake, why not just make all the methods synchronized? You have two reasons not to do so:

  • Synchronizing methods takes time. Java has to acquire a lock (see the next section) on the object being synchronized, run the method, and then release the lock. But before it can do that, it has to check to make sure that some other thread doesn’t already have a lock on the object. All this work takes time.
  • More important, synchronizing all your methods defeats the purpose of multithreading, so you should synchronize only those methods that require it.

Remember The synchronized keyword doesn’t block all access to an object. Other threads can still run unsynchronized methods of the object while the object is locked.

Technical stuff The Object class provides three methods that can let synchronized objects coordinate their activities. The wait method puts a thread in the waiting state until some other thread calls either the object’s notify or (more commonly) notifyAll method. These methods are useful when one thread has to wait for another thread to do something before it can proceed. The classic example is a banking system in which one thread makes withdrawals and the other makes deposits. If a customer’s account balance drops to zero, the thread that makes withdrawals can call wait; then the thread that makes deposits can call notifyAll. That way, each time a deposit is made, the withdrawal thread can recheck the customer’s account balance to see whether it now has enough money for the customer to make a withdrawal.

Creating a Lock

A few years back, Java version 1.5 introduced many new threading features. One such feature was the introduction of locks. A lock can take the place of Java’s synchronized keyword, but a lock is much more versatile. Listings 1-11 and 1-12 illustrate the use of a lock.

LISTING 1-11 Creating CountDownClock Threads (Again)

import java.util.concurrent.ScheduledThreadPoolExecutor;

public class DoTwoThingsLocked {

ScheduledThreadPoolExecutor pool =

new ScheduledThreadPoolExecutor(2);

CountDownClockLocked clock =

new CountDownClockLocked();

public static void main(String[] args)

{

new DoTwoThingsLocked();

}

DoTwoThingsLocked()

{

pool.execute(clock);

pool.execute(clock);

pool.shutdown();

}

}

LISTING 1-12 Using a Lock

import java.util.concurrent.locks.ReentrantLock;

public class CountDownClockLocked extends Thread

{

ReentrantLock lock = new ReentrantLock();

public void run()

{

lock.lock();

for (int t = 20; t >= 0; t--)

{

System.out.println("T minus " + t);

try

{

Thread.sleep(1000);

}

catch (InterruptedException e)

{}

}

lock.unlock();

}

}

Listing 1-12 is remarkably similar to Listing 1-10. The only significant difference is the replacement of the synchronized keyword by calls to ReentrantLock methods.

At the start of Listing 1-12, the code declares the variable lock — an instance of the ReentrantLock class. This lock object is like a gas station’s restroom key: Only one thread at a time can have the lock object. When one thread gets the lock object — by calling lock.lock() at the start of the run method — no other thread can get past the lock.lock() call. A second thread must wait at the lock.lock() call until the “restroom key” becomes available. In Listing 1-12, the key becomes available only when the first thread reaches the lock.unlock() statement. After the first thread calls lock.unlock(), the second thread proceeds into the method’s for loop.

The overall result is the same as the output of Listings 1-9 and 1-10. In this example, using a lock is no better than using Java’s synchronized keyword. But Java 1.5 has several kinds of locks, and each kind of lock has its own useful features.

Coping with Threadus Interruptus

You can interrupt another thread by calling its interrupt method, provided that you have a reference to the thread, as in this example:

t.interrupt();

Here the thread referenced by the t variable is interrupted. Now all the interrupted thread has to do is find out that it has been interrupted and respond accordingly. That’s the topic of the following sections.

Finding out whether you’ve been interrupted

As you’ve already seen, several methods of the Thread class, including sleep and yield, throw InterruptedException. Up until now, I’ve told you to simply ignore this exception — and in many cases, that’s appropriate. Many (if not most) threads, however, should respond to InterruptedException in one way or another. In most cases, the thread should terminate when it’s interrupted.

Unfortunately, finding out whether a thread has been interrupted isn’t as easy as it sounds. InterruptedException is thrown when another thread calls the interrupt method on this thread while the thread is not executing. That’s why the methods that can cause the thread to give up control to another thread throw this exception. That way, when the thread resumes execution, you know that it was interrupted.

The yield and sleep methods aren’t the only way for control to be wrested away from a thread, however. Sometimes the thread scheduler just steps in and says, “You’ve had enough time; now it’s someone else’s turn to play.” If that happens and then some other thread calls your thread’s interrupt method, InterruptedException isn’t thrown. Instead, a special flag called the interrupted flag is set to indicate that the thread was interrupted. You can test the status of this flag by calling the static interrupted method.

Unfortunately, that means your threads have to check twice to see whether they have been interrupted. The usual way to do that is to follow this form:

public void run()

{

boolean done = false

boolean abort = false;

while(!done)

{

// do the thread_s work here

// set done to true when finished

try

{

sleep(100); // sleep a bit

}

catch(InterruptedException e)

{

abort = true;

}

if (Thread.interrupted())

abort = true;

if (abort)

break;

}

}

Here the boolean variable abort is set to true if InterruptedException is thrown or if the interrupted flag is set. Then, if abort has been set to true, a break statement is executed to leave the while loop. This scheme has a million variations, of course, but this one works in most situations.

Aborting the countdown

To illustrate how you can interrupt threads, Listing 1-13 shows yet another version of the countdown application. This version aborts the countdown if something goes wrong with any of the launch events.

To simplify the code a bit, I assume that things aren’t going well at NASA, so every launch event results in a failure that indicates a need to abort the countdown. Thus, whenever the start time for a LaunchEvent arrives, the LaunchEvent class attempts to abort the countdown. It goes without saying that in a real launch-control program, you wouldn’t want to abort the launch unless something actually does go wrong.

LISTING 1-13 The Countdown Application with Aborts

import java.util.ArrayList;

public class CountDownApp→3

{

public static void main(String[] args)

{

CountDownClock clock = new CountDownClock(20);

ArrayList<Runnable> events =

new ArrayList<Runnable>();

events.add(new LaunchEvent(16,

"Flood the pad!", clock));

events.add(new LaunchEvent(6,

"Start engines!", clock));

events.add(new LaunchEvent(0,

"Liftoff!", clock));

clock.start();

for (Runnable e : events)

new Thread(e).start();

}

}

interface TimeMonitor

{

int getTime();

void abortCountDown();→25

}

class CountDownClock extends Thread

implements TimeMonitor

{

private int t;

public CountDownClock(int start)

{

this.t = start;

}

public void run()

{

boolean aborted = false;→40

for (; t >= 0; t--)

{

System.out.println("T minus " + t);

try

{

Thread.sleep(1000);

}

catch (InterruptedException e)

{

aborted = true;→50

}

if (Thread.interrupted())

aborted = true;→53

if (aborted)→54

{

System.out.println(

"Stopping the clock!");

break;

}

}

}

public int getTime()

{

return t;

}

public synchronized void abortCountDown()→68

{

Thread[] threads =

new Thread[Thread.activeCount()];→71

Thread.enumerate(threads);→72

for(Thread t : threads)→73

t.interrupt();

}

}

class LaunchEvent implements Runnable

{

private int start;

private String message;

TimeMonitor tm;

public LaunchEvent(int start, String message,

TimeMonitor monitor)

{

this.start = start;

this.message = message;

this.tm = monitor;

}

public void run()

{

boolean eventDone = false;

boolean aborted = false;→95

while (!eventDone)

{

try

{

Thread.sleep(10);

}

catch (InterruptedException e)

{

aborted = true;→104

}

if (tm.getTime() <= start)

{

System.out.println(this.message);

eventDone = true;

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

tm.abortCountDown();

}

if (Thread.interrupted())

aborted = true;→114

if (aborted)→115

{

System.out.println(

"Aborting " + message);

break;

}

}

}

}

The following paragraphs point out the highlights of this program:

  • →3 The CountDownApp class itself hasn’t changed. That’s the beauty of object-oriented programming. Although I changed the implementations of the CountDownClock and LaunchEvent classes, I didn’t change the public interfaces for these classes. As a result, no changes are needed in the CountDownApp class.
  • →25 The LaunchEvent class needs a way to notify the CountDown Timer class that the countdown should be aborted. To do that, I added an abortCountDown method to the TimeMonitor interface.
  • →40 The run method of the CountDownClass uses a boolean variable named aborted to indicate whether the thread has been interrupted. This variable is set to true in line 50 if InterruptedException is caught. It’s also set to true in line 53 if Thread.interrupted() returns true.
  • →54 If the aborted field has been set to true, it means that the thread has been interrupted, so the message Stopping the clock! is displayed, and a break statement exits the loop. Thus the thread is terminated.
  • →68 The abortCountDown method is synchronized. That happens because any of the LaunchEvent objects can call it, and there’s no guarantee that they won’t all try to call it at the same time.
  • →71 The abortCountDown method starts by creating an array of Thread objects that’s large enough to hold all the active threads. The number of active threads is provided by the activeCount method of the Thread class.
  • →72 The abortCountDown method calls the enumerate method of the Thread class to copy all the active threads into this array. Note that this method is static, so you don’t need a reference to any particular thread to use it. (The activeCount method used in line 69 is static too.)
  • →73 An enhanced for loop is used to call the interrupt method on all the active threads. That method shuts down everything.
  • →95 Like the CountDownClock class, the LaunchEvent class uses a boolean variable to indicate whether the thread has been interrupted. This variable is set if InterruptedException is caught in line 104 or if Thread.interrupted() returns true in line 114; then it’s tested in line 115. If the aborted variable has been set to true, the thread prints a message indicating that the launch event has been aborted, and a break statement is used to exit the loop and (therefore) terminate the thread.

When you run this version of the countdown application, the console output will appear something like this (minor variations might occur because of the synchronization of the threads):

T minus 20

T minus 19

T minus 18

T minus 17

T minus 16

Flood the pad!

ABORT!!!!

Stopping the clock!

Aborting Flood the pad!

Aborting Start engines!

Aborting Liftoff!