Previous | Next | Trail Map | Writing Applets | Overview of Applets


Threads in Applets: Examples

This page discusses two examples of using threads in applets. The first applet, AnimatorApplet, shows how to use a thread to perform repeated tasks. AnimatorApplet is from the page Creating the Animation Loop(in the Creating a User Interface trail). The second applet this page discusses, SoundExample, shows how to use threads for one-time initialization tasks. SoundExample is featured on the page Playing Sounds(in the Writing Applets trail).

This page does not explain basic thread code. To learn about the Java implementation of threads, refer to Threads of Control(in the Writing Java Programs trail).

Using a Thread to Perform Repeated Tasks

An applet that performs the same task over and over again typically should have a thread with a while (or do...while) loop that performs the task. A typical example is an applet that performs timed animation, such as a movie player or a game. Animation applets need a thread that requests repaints at regular intervals. Another example is an applet that reads data supplied by a server-side application. (See Using a Server to Work Around Security Restrictions(in the Writing Applets trail) for such an example.)

Applets typically create threads for repetitive tasks in the applet start() method. Creating the thread there makes it easy for the applet to stop the thread when the user leaves the page. All you need to do is implement the stop() method so that it stops the applet's thread. When the user returns to the applet's page, the start() method is called again, and the applet can again create a thread to perform the repetitive task.

Below is AnimatorApplet's implementation of the start() and stop() methods. (Here is all of the applet's source code.)

public void start() {
    if (frozen) {
        //Do nothing.  The user has requested that we
        //stop changing the image.
    } else {
        //Start animating!
        if (animatorThread == null) {
            animatorThread = new Thread(this);
        }
        animatorThread.start();
    }
}

public void stop() {
    animatorThread = null;
}

The this in new Thread(this) indicates that the applet provides the body of the thread. It does so by implementing the java.lang Runnable interface, which requires the applet to provide a run() that forms the body of the thread. We'll discuss AnimatorApplet's run() more a little later.

In AnimatorApplet, the browser isn't the only caller of the start() and stop() methods. The applet calls them itself when the user clicks on the applet's display area to indicate that the animation should stop. The applet uses the frozen instance variable to keep track of whether the user has requested that the animation stop.

You might have noticed that nowhere in the AnimatorApplet class is the Thread stop() method called. This is because calling the Thread stop() method is like clubbing the thread over the head. It's a drastic way to get the thread to stop what it's doing. Instead, you can write the thread's run() method in such a way that the thread will gracefully exit when you tap it on the shoulder. This shoulder tap comes in the form of setting to null an instance variable of type Thread.

In AnimatorApplet, this instance variable is called animatorThread. The start() method sets it to refer to the newly created Thread object. When the applet needs to kill the thread, it sets animatorThread to null. This kills the thread not by making it be garbage collected -- it can't be garbage collected while it's runnable -- but because at the top of its loop, the thread checks animatorThread, continuing or exiting depending on the value of animatorThread. Here's the relevant code:

public void run() {
    . . .
    while (Thread.currentThread() == animatorThread) {
        ...//Display a frame of animation and then sleep.
    }
}

If animatorThread refers to the same thread as the currently executing thread, the thread continues executing. If, on the other hand, animatorThread is null, the thread exits. If animatorThread refers to another thread, then a race condition has occurred: start() has been called so soon after stop() (or this thread has taken such a long time in its loop) that start() has created another thread before this thread reached the top of its while loop. Whatever the cause of the race condition, this thread should exit.

For more information about AnimatorApplet, go to Creating the Animation Loop(in the Creating a User Interface trail).

Using a Thread to Perform One-Time Initialization

If your applet needs to perform some initialization task that can take a while, you should consider ways of performing the initialization in a thread. For example, anything that requires making a network connection should generally be done in a background thread. Fortunately, GIF and JPEG image loading is automatically done in the background (using threads that you don't need to worry about).

Sound loading unfortunately, is not guaranteed to be done in the background. In current implementations, the Applet getAudioClip methods don't return until they've loaded all the audio data. As a result, if you want to preload sounds, you might want to create one or more threads to do so.

Using a thread to perform a one-time initialization task for an applet is a variation of the classic producer/consumer scenario. The thread that performs the task is the producer, and the applet is the consumer. Synchronizing Threads(in the Writing Java Programs trail) discusses how to use Java threads in a producer/consumer scenario.

SoundExample adheres closely to the model presented in Synchronizing Threads. Like the Synchronizing Threads example, SoundExample features three classes:

For more information on SoundExample, go to Playing Sounds(in the Writing Applets trail).


Previous | Next | Trail Map | Writing Applets | Overview of Applets