3.2 Multi-Threaded Programs


3.2 Multi-Threaded Programs

Concurrency occurs in Java programs when more than one thread is alive. Remember from Chapter 2 that a thread is alive if it has started but has not yet terminated. In this section, we present an example of a simple Java multi-threaded program that has two concurrently active threads in addition to the main thread of execution present in every Java program. The threads in the example program do not interact directly. The topic of how threads interact is left to succeeding chapters.

3.2.1 ThreadDemo Example – Model

The example program drives the display depicted in Figure 3.16. Each of the threads, A and B, can be run and paused by pressing the appropriate button. When a thread is run, the display associated with it rotates. Rotation stops when the thread is paused. When a thread is paused, its back ground color is set to red and when it is running, the background color is set to green. The threads do not interact with each other; however they do interact with the Java main thread of execution when the buttons are pressed.

image from book
Figure 3.16: ThreadDemo display.

The behavior of each of the two threads in the applet is modeled by the following ROTATOR process:

 ROTATOR = PAUSED, PAUSED  = (run->RUN | pause->PAUSED), RUN     = (pause->PAUSED |{run,rotate}->RUN).

The process cannot perform the rotate action until it moves into the RUN state. This can only occur after the run action, which models pushing the Run button. When the pause action occurs – modeling the Pause button – the process moves back to the PAUSED state in which the rotate action cannot take place. The model implies that the implementation of ROTATOR runs forever – there is no way of stopping it. It is not good practice to program threads which run forever; they should terminate in an orderly manner when, for example, the Applet.stop() method is called by a browser. As we discussed in the previous chapter, the designers of Java do not recommend using Thread.stop() to terminate the execution of a thread. Instead, they suggest the use of Thread.interrupt() which raises the InterruptedException that allows a thread to clean up before terminating. We can include termination in the ROTATOR process as shown below. The corresponding LTS is depicted in Figure 3.17.

 ROTATOR = PAUSED, PAUSED  = (run->RUN |pause->PAUSED           |interrupt->STOP), RUN     = (pause->PAUSED |{run,rotate}->RUN           |interrupt->STOP).

image from book
Figure 3.17: ROTATOR.

This revised model includes the effect of an interrupt action. Whether the ROTATOR process is in the paused or running state, the interrupt takes it into a final state in which no further actions are possible, i.e. it is terminated. The model for the ThreadDemo program consisting of two copies or instances of the ROTATOR thread is shown in Figure 3.18.

image from book
Figure 3.18: ThreadDemo model.

We have relabeled the a.interrupt and b.interrupt actions to be the same action stop, indicating that we always interrupt both threads at the same time, when the browser calls Applet.stop(). Having constructed the model, we can animate it using the LTSA tool to check that its behavior corresponds to the behavior we expect of the ThreadDemo applet. Figure 3.19 shows a screen shot of the LTSA Animator window. As described in Chapter 2, those actions that can be chosen for execution are ticked. In the figure, the action a.run has put process a in the state where a.rotate actions can occur while process b cannot perform its b.rotate action since b.run has not occurred.

image from book
Figure 3.19: LTSA Animator window for THREAD_DEMO.

In fact, in the implementation, the environment is provided by the main thread of execution of the Java program. We can of course also model this main thread as a process that shares the actions. The display can rotate at any time and the buttons can be pushed at any time. Consequently, this main thread can be modeled as:

 MAIN = ({a.rotate,a.run,a.pause,stop,          b.rotate,b.run,b.pause}->MAIN).

Composing MAIN with THREAD_DEMO does not modify the behavior of THREAD_DEMO since it does not provide any additional ordering constraints on the actions.

3.2.2 ThreadDemo Example – Implementation

The implementation for the process is provided by the Rotator class, which implements the Runnable interface as shown in Program 3.1. The run() method simply finishes if an InterruptedException raised by Thread.interrupt() occurs. As described in the previous chapter, when the run() method exits, the thread which is executing it terminates.

Program 3.1: Rotator class.

image from book
 class Rotator implements Runnable {  public void run() {     try {       while(true) ThreadPanel.rotate();     } catch(InterruptedException e) {}   } }
image from book

The details of suspending and resuming threads when buttons are pressed are encapsulated in the ThreadPanel class. The run() method simply calls ThreadPanel.rotate() to move the display. If the Pause button has been pressed, this method suspends a calling thread until Run is pressed. We use the ThreadPanel class extensively in programs throughout the book. The methods offered by this class relevant to the current example are listed in Program 3.2.

The ThreadPanel class manages the display and control buttons for the thread that is created by a call to the start() method. The thread is created from the class DisplayThread which is derived from Thread. The implemention of start() is given below:

Program 3.2: ThreadPanel class.

image from book
 public class ThreadPanel extends Panel {   // construct display with title and segment color c   public ThreadPanel(String title, Color c) {...}   // rotate display of currently running thread 6 degrees   // return value not used in this example   public static boolean rotate()          throws InterruptedException {...}   // create a new thread with target r and start it running   public void start(Runnable r) {...}   // stop the thread using Thread.interrupt()   public void stop() {...} }
image from book

 public void start(Runnable r) {      thread = new DisplayThread(canvas,r,...);      thread.start(); }

where canvas is the display used to draw the rotating segment. The thread is terminated by the stop() method using Thread.interrupt() as shown below:

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

ThreadPanel delegates calls to rotate() to DisplayThread. The relationship between these classes, the applet and the Rotator class is depicted in the class diagram of Figure 3.20. Note that rotate() is a static method which determines the particular thread instance to which it applies by calling the method Thread.currentThread(). This returns a reference to the currently running thread, which, of course, is the only thread which can have called the method.

image from book
Figure 3.20: ThreadDemo class diagram.

The Applet class ThreadDemo creates the two ThreadPanel displays when it is initialized and the two threads when it is started. The class is listed in Program 3.3.

Program 3.3: ThreadDemo applet class.

image from book
 public class ThreadDemo extends Applet {   ThreadPanel A;   ThreadPanel B;   public void init() {     A = new ThreadPanel("Thread A",Color.blue);     B = new ThreadPanel("Thread B",Color.blue);     add(A);     add(B);   }   public void start() {     A.start(new Rotator());     B.start(new Rotator());   }   public void stop() {     A.stop();     B.stop();   } }
image from book

In section 2.2.3, we saw that Java provides a standard set of operations on threads including suspend() and resume() which the reader might surmise have been used to suspend and resume the execution of the threads in response to pushing the buttons. In fact, we cannot use the operations directly in the implementation of the ThreadDemo program for the following reason. The rotate() method acquires and releases resources from the graphical interface provided by the browser in which the applet runs. If we used suspend(), a thread could be suspended at some arbitrary time when Pause was pressed. In particular, it could be suspended while it was holding on to display resources. This can cause some browsers to hang or deadlock[1]. Consequently, the threads in the program are suspended using the methods Object.wait() and Object.notify(). We defer an explanation of how these work until Chapter 5 and consider the problem of deadlock in Chapter 6.

[1] For just this reason, stop (), suspend () and resume () are now deprecated.




Concurrency(c) State Models & Java Programs
Concurrency: State Models and Java Programs
ISBN: 0470093552
EAN: 2147483647
Year: 2004
Pages: 162

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net