8.3 Cooperative and Competitive Synchronization

 < Day Day Up > 



8.3 Cooperative and Competitive Synchronization

Synchronization is used in a program for two reasons: allow threads to compete for a resource or allow them to coordinate activities. These two concepts were introduced in Chapter 1 in terms of baking a pie. Competitive synchronization in this case occurred when a shared resource (the bowl in which the pie crust and filling were to be mixed) was used. Cooperative synchronization occurred when two or more asynchronous activities had to wait for each other for a specific event to occur. So far in the text, only competitive synchronization has been covered, but this chapter introduces cooperative synchronization.

To understand how cooperative synchronization can occur in a problem we will use the animator from Chapter 7. The problem that illustrates cooperative synchronization is when a thread wishes to wait until the animator has finished moving an object before continuing to execute. To see how this problem occurs, consider Exhibit 1 (Program8.1), [1] which implements a simple animation of two threads that wait a random amount of time and then move a ball across the screen. The logic in the run method simply creates a path for the ball to travel, to the EAST if it was previously going WEST, to the NORTH if it was going SOUTH, etc. The thread then goes to sleep while the GUI thread calls the draw method for the ball, which moves the ball. The draw method uses the Path variable that was created in the run method to control the steps in the animation. When the ball reaches its destination, when the path has no more steps, it will then simply wait until the thread is done sleeping and reverse its direction and move again.

Exhibit 1: Program8.1: Thread Animation with No Coordination

start example

 import java.awt.*; import java.util.*; import animator.*; /**  * This class animates a ball in a thread using the animator  * component but fails because the thread is not coordinated  * with the GUI thread calling the draw method.  */ public class ConcurrentBall implements DrawListener, Runnable {   static final int EAST = 0;   static final int WEST = 1;   static final int NORTH = 2;   static final int SOUTH = 3;   int direction;   Path myPath;   Random random;   Animator animator;   /**    * Constructor. Just save information for this ball.    */   public ConcurrentBall(Animator animator, int direction) {     this.direction = direction;     random = new Random(direction);     this.animator = animator;   }   /**    * The run method simulates an asynchronous ball. The    * myPath variable is set here and used in the draw method    * and is intended to coordinate the ball thread running in    * this method and the GUI thread (from the animator)    * running in the draw method. But, no coordination is in    * place, and this approach fails.    */   public void run() {     animator.addDrawListener(this);     try {       while(true) {         if (direction = = SOUTH) {           myPath = new StraightLinePath(410, 205, 10, 205, 50);           direction = NORTH;         }         else if (direction = = NORTH) {           myPath = new StraightLinePath(10, 205, 410, 205, 50);           direction = SOUTH;         }         else if (direction = = EAST) {           myPath = new StraightLinePath(205, 410, 205, 10, 50);           direction = WEST;         }         else if (direction = = WEST) {           myPath = new StraightLinePath(205, 10, 205, 410, 50);           direction = EAST;         }       Thread.sleep(random.nextInt(10000));       }     } catch (InterruptedException e) {     }   }   /**    * Draw is called each time through the animator loop to draw    * the object. It simply uses the path to calculate the    * position of this object and then draws itself at that    * position.    */   public void draw(DrawEvent de) {     Point p = myPath.nextPosition();     Graphics g = de.getGraphics();     g.setColor(Color.red);     g.fillOval((int)p.getX(), (int)p.getY(), 15, 15);   }   /**    * The main method just creates the animator and    * the ball threads and starts them running.    */   public static void main(String args[]) {     Animator animator = new Animator();     ConcurrentBall cb1 = new ConcurrentBall(animator, WEST);     (new Thread(cb1)).start();     ConcurrentBall cb2 = new ConcurrentBall(animator, NORTH);     (new Thread(cb2)).start();     animator.setVisible(true);   } } 

end example

Threads were used to make this program sleep a random amount of time between movement, as the sleep could be made part of the steps in the activity. This behavior of inserting a random sleep into the thread cannot be easily accomplished unless the balls are in threads. (A more complex example using the gas station simulation from Chapter 3 is presented later; utilizing sleep as part of the problem solution is easy to implement, as the cars will be in separate threads.)

When this program is run and the balls are moving quickly, the solution in Exhibit 1 (Program8.1) appears to be correct; however, as with everything else regarding asynchronous activities, we cannot test the program to prove it is correct. Care must be taken to implement the program correctly or the results may not be as expected. To see this, run the animation and pull the speed control all the way to the left, causing the program to go at its slowest speed. A disturbing behavior then becomes apparent. The ball moves some portion of the way across the screen, suddenly jumps to the far side of the screen, and begins moving in the opposite direction.

The reason the ball jumps to the other side of the screen is that the ball thread wakes up before the GUI thread has finished moving the ball to the other side of the screen. When the ball thread wakes up it creates a new path object and the draw method now uses this new path object immediately, thus moving the ball to the other side of the screen where this new path begins. This is not the intended behavior. The problem here is that the GUI thread and the ball thread are uncoordinated. The ball thread should actually suspend until the GUI thread has completed moving the ball across the screen and then should begin its sleep.

Making the program behave so that the ball thread does not start to sleep until the movement of the ball is completed is an example of cooperative synchronization. Somehow these two threads must be coordinated. How to coordinate these threads (i.e., how to achieve cooperative synchronization) is the topic of the remainder of this chapter. Once these techniques have been covered, they are combined in Chapter 9 with the competitive synchronization techniques already discussed. As will be seen, combining these techniques allows for the development of very powerful and extensible programs.

[1]Note that the animations in this chapter all use the animator component developed in Chapter 8 and stored in the animator package that is available with this book. The useAnimator.bat file will correctly set up all the directories needed to run these programs.



 < Day Day Up > 



Creating Components. Object Oriented, Concurrent, and Distributed Computing in Java
The .NET Developers Guide to Directory Services Programming
ISBN: 849314992
EAN: 2147483647
Year: 2003
Pages: 162

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