More on Starting, Stopping, and Joining

Consider this revision to the Animate example:

import java.applet.Applet;

public class Animate extends Applet {
    TimerThread t;
    public void start() {
        if (t == null)
            t = new TimerThread(this, 500);
        t.start();
    }

    public void stop() {
        t.shouldRun = false;
        try {
            t.join();
        } catch (InterruptedException e) {}
        // t = null;
     }
}

In our last version of the Animate applet (see Section 2.3,” earlier in this chapter), the start() method of the applet created a new TimerThread object and started it. But what if we had only created the TimerThread once? In the example just shown, we once again create a new TimerThread in the start() method of the applet; however, since we know the thread will be stopped in the stop() method, we try to restart the stopped thread in the start() method. In other words, we create the TimerThread only once and use this one thread object to start and stop the animation. By starting and stopping a single TimerThread, we do not need to create a new instance of TimerThread every time the applet is started, and the garbage collector will not need to clean up the TimerThread instance that’s left when the applet is stopped and the TimerThread dereferenced.

But will this work? Unfortunately, the answer is no. It turns out that when a thread is stopped, the state of the thread object is set so that it is not restartable. In our case, when we try to restart the thread by calling the TimerThread’s start() method, nothing happens. The start() method won’t return an exception condition, but the run() method also won’t be called. The isAlive() method also won’t return true. In other words, never restart a thread. An instance of a thread object should be used once and only once.

Can an already stopped thread be stopped? At first glance, this may seem an odd question. But the answer is yes, and the reason is that it avoids a race condition that would occur otherwise. We know there are two ways a thread can be stopped, so you could stop a thread that has already exited because its run() method terminated normally. If the Thread class did not allow the stop() method to be called on a stopped thread, this would require us to check if the thread was still running before we stopped it, and we’d have to avoid a race condition in which the run() method could terminate in between the time when we checked if the thread was alive and when we called the stop() method. This would be a big burden on the Java developer, so, instead, the stop() method can be called on a thread that has already stopped.

What happens when we call the join() method for a thread that was stopped a long time ago? In the examples so far, we assumed the usage of the join() method was to wait for a thread to complete or to stop. But this assumption is not necessary; if the thread is already stopped, it will return immediately. This may seem obvious, but it should be noted that a race condition would have resulted if the join() method had required that the thread be alive when the method was first called.

What would be the best way to join() with more than one thread? Let’s look at the following code:

import java.applet.Applet;

public class MyJoinApplet extends Applet {
    Thread t[] = new Thread[30];
    public void start() {
        for (int i=0; i<30; i++) {
            t[i] = new CalcThread(i);
            t[i].start();
        }
    }

    public void stop() {
        for (int i=0; i<30; i++) {
            try {
                 t[i].join();
            } catch (InterruptedException e) {}
        }
    }
}

In this example, we start 30 CalcThread objects. We have not actually defined the CalcThread class, but for this example, we assume it is a class that is used to calculate part of a large mathematical algorithm. In the applet’s stop() method, we execute a loop waiting for all the started threads to be finished. Is this the best way to wait for more than one thread? Since it is possible to join() with an already stopped thread, it is perfectly okay to join() with a group of threads in a loop, even if the threads finish in an order different than the order in which they were started. No matter how we might have coded the join() loop, the time to complete the join() will be the time it takes for the last thread to finish.

Of course, there may be cases where a specific joining mechanism is desired, but this depends on details other than the threading system. There is no performance penalty to pay for joining in an order that is not the order of completion.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset