Threading an Applet

Applets are embeddable Java applications that are expected to start and stop themselves on command, possibly many times in their lifetime. A Java-enabled web browser normally starts an applet when the applet is displayed and stops it when the user moves to another page or (in theory) when the user scrolls the applet out of view. To conform to this API, we would like an applet to cease its nonessential activity when it is stopped and resume it when started again. We’ll talk about applets in Chapter 23, but it’s not really essential to know about them here. We’ll just use this as a more realistic example and as a transition to talk about our next topic, synchronization.

In this section, we will build UpdateApplet, a simple base class for an applet that maintains a thread to automatically update its display at regular intervals. UpdateApplet handles the basic creation and termination of the thread in the Applet’s start() and stop() methods:

    public class UpdateApplet extends java.applet.Applet
        implements Runnable
    {
        Thread thread;
        boolean running;
        int updateInterval = 1000;

        public void run() {
            while ( running )
            {
                repaint();
                try {
                    Thread.sleep( updateInterval );
                } catch ( InterruptedException e ) {
                    System.out.println("interrupted...");
                    return;
                }
            }
        }

        public void start() {
            System.out.println("starting...");
            if ( !running ) // naive approach
            {
                running = true;
                thread = new Thread(this);
                thread.start();
            }
        }

        public void stop() {
            System.out.println("stopping...");
            thread.interrupt();
            running = false;
        }
    }

UpdateApplet is a Runnable object that alternately sleeps and calls its repaint() method. (There’s nothing to paint, though, so running this applet is kind of boring. Later we’ll subclass it to implement a digital clock.) It has two other public methods: start() and stop(). These are methods of the Applet class we are overriding; don’t confuse them with the similarly named methods of the Thread class. These start() and stop() methods are called by the web browser or applet viewer to tell the applet when it should and should not be running.

UpdateApplet illustrates an environmentally friendly way to deal with threads in a simple applet. UpdateApplet simply dismisses its thread each time the applet is stopped and recreates it if the applet is restarted. When UpdateApplet’s start() method is called, we first check to make sure there is no currently running thread by checking the running flag. We then create one to begin our execution. When our applet is subsequently asked to stop, we set the flag indicating that it should stop and make sure the thread is awake by invoking its interrupt() method. In this way, we are sure to catch the thread either at the beginning of its next iteration or when it goes to sleep.

With UpdateApplet doing all the work for us, we can create the world’s simplest clock applet with just a few lines of code. Figure 9-3 shows our Clock.

The Clock applet

Figure 9-3. The Clock applet

Here’s the code:

    //file: Clock.java
    public class Clock extends UpdateApplet {
        public void paint( java.awt.Graphics g ) {
            g.drawString( new java.util.Date().toString(), 10, 25 );
       }
    }

The java.util.Date().toString() method creates a string that contains the current time.

Issues Lurking

Our applet seems pretty straightforward and, in fact, works as advertised. But some things in it should concern us when we’re thinking about threads. Let’s look at that quick check of the running flag before we start our new thread:

    if ( !running ) // naive approach
    {
        running = true;
        ... /* start thread */

Now, an Applet’s start() and stop() methods are guaranteed to be called in sequence and probably by the same controlling thread. As a result, this check for the existence of the running thread in start() may not seem necessary here. The stop() method should always be called before the start() method is invoked again. But, in the style of defensive programming the test seems like a good thing to do, right? That may be so, but, in general, it’s not enough to prevent bad things from happening. The test may prevent a simple case of misaligned stop() and start() calls, but the bigger question lurking here is, What happens if start() and stop() were called repeatedly or in very quick succession in a multithreaded environment? In the extreme case, it would be possible for two threads to enter the test at about the same time and there is the chance that we could end up with multiple threads started and out of our control. What is needed is a real way to gain exclusive access to a resource (our flag) for a period of time. That’s what synchronization is all about, and we’ll cover it in detail in the next section and throughout the rest of this chapter.

With synchronization, we might also consider more complex scenarios for our applet, such as keeping our thread alive but dormant while the applet is stopped. This would allow us to preserve expensive setup like network connections and clean them up later if necessary.

Get Learning Java, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.