Step 5: Interfaces and Threads

You are probably familiar with multitasking if you have an operating system such as Windows 95 or NT. Multitasking is having multiple programs perform tasks concurrently. For example, you could play a game while a document is printing and another program is performing a lengthy calculation, such as finding all primes up to a million.

Multithreading takes this one further step. A thread is a path of execution in a program. Multithreading allows your program to do two things at once (or three things, or ten...whatever). A common application of multithreading in applications is to perform a task in the background, such as printing, while the user continues to work on the document. In Java, multithreading lets your applet do stuff while the browser does its. This is great for animations, video, and other multimedia that require continuous updating. This is also great for ClockApplet, which needs a mechanism to display the time every second.

Interfaces

An applet supports multithreading by implementing the Runnable interface. What's that again? An interface is a "contract for services" that a class implementing it must provide. That is, a class that implements an interface is expected to (and indeed must) define all the methods specified by the interface. (Note to C++ programmers: Interfaces are like purely abstract classes.) A class X that implements an interface Y is a Y, and can be treated as such in your program.

Let's see how an applet implements the Runnable interface. Make the following modification to the class declaration of ClockApplet:

public class ClockApplet extends Applet implements Runnable {

The implements keyword followed by the interface name does the trick. You're not done yet though. As explained above, you now need to define all the methods of Runnable as methods in ClockApplet. (There's only one method defined in Runnable: run().) Before we do that, first add a couple statements to the Fields section:

//
// Fields
//

private Thread thread = new Thread(this);
private Date now = new Date();

The first statement creates a new Thread object called thread. Note the keyword this: this references the class it's contained in, which in this case is ClockApplet. Passing this to Thread tells Thread that this contains a run() method. (This is the reason why ClockApplet needs to implement the Runnable interface. Thread needs to make sure that the class has a run() method, because Thread will call it.) The second statement creates a Date object called now that is initialized to the current date and time. (A Date object does not update itself continuously though.)

The run() method, along with several others, is defined as follows (add this after the update() method):

//
// Thread functions
//

public void start() {
	if(thread.isAlive())
		thread.resume();
	else
		thread.start();
}

public void run() {
	while(true) {
		now = new Date(); // Get current time
		repaint();

		try {
			thread.sleep(500);
		}
		catch(InterruptedException e) {
		}
	}
}

public void stop() {
	thread.suspend();
}

public void destroy() {
	thread.stop();
}

The run() method is the sole method required when implementing Runnable. Before we get to that, let's examine the applet life cycle.

The Applet Life Cycle

There are four stages in the life cycle of an applet. These are:

Threads

We override the start(), stop(), and destroy() methods to control the execution of our new thread. Here they are again:

public void start() {
	if(thread.isAlive())
		thread.resume();
	else
		thread.start();
}

public void stop() {
	thread.suspend();
}

public void destroy() {
	thread.stop();
}

In the start() method, we first call the isAlive() method of thread to check if the thread is "alive." When the applet first starts, the thread is "dead," so we call thread.start() to start it running. (This in turn calls our run() method, which we'll look at in a minute.) If the applet is restarted after having been suspended though, the thread is already alive, so we call thread.resume() to simply resume execution.

In the stop() method, we call thread.suspend() to suspend the thread's execution. After all, the clock doesn't need updating when the user isn't looking at it! Finally, we call thread.stop() in the destroy() method to kill the thread, once and for all.

run in Detail

We finally get to the heart of the thread, the run() method:

public void run() {
	while(true) {
		now = new Date(); // Get current time
		repaint();

		try {
			thread.sleep(500);
		}
		catch(InterruptedException e) {
		}
	}
}

Ah, a new keyword! The while statement executes a body of code while a condition is true. Here is the syntax:

while(boolean-expression)
	loop-body

If boolean-expression is true, loop-body is executed. Then boolean-expression is checked again, and so on. In our run() method, since true is always true, we've created an infinite loop. (It's not all that infinite though; Java's threading mechanism can break the loop if we call thread.stop().)

Inside the loop, we create a new Date object and assign it to now. Using new Date() always gets the current date and time. We call repaint() to update the clock display, and then call the sleep() method of thread to suspend it for 500 milliseconds, or half a second. The sleep() method can throw an InterruptedException, so we need to catch it. You can simply ignore the exception, as we do here.

Why do we update the clock every half a second? We could update it every second (by using 1000 instead of 500), but the timing is not completely precise. Using 500 provides a better "resolution."

If you compile the applet now, nothing will move. That's because we haven't drawn the clock hands yet. In preparation for that, add the following statement to the paint() method:

public void paint(Graphics g) {
	drawFace();
	g.drawImage(faceBuffer, 0, 0, null);
}

The new drawFace() method draws the clock hands (add this after createFace()):

// Draw all clock hands
private void drawFace() {
	Graphics g = faceBuffer.getGraphics();
	g.drawImage(tickImage, 0, 0, null);
}

This calls the getGraphics() method of faceBuffer to get a Graphics object that's linked to it, then calls drawImage() to copy the contents of tickImage onto it.

If you want, you can compile the applet and test it. Although nothing seems to have changed, the clock face is in fact being updated every half a second. In the next step we'll flesh out drawFace().


1