|
|
< Day Day Up > |
|
Synchronization is used to coordinate asynchronous activities, such as threads. Up to this point in the book, synchronization of asynchronous activities has always been on shared resources; this is called competitive synchronization , because the activities are always competing for the shared resource. However, at times activities must synchronize on an event that must occur before all threads can continue; this type of synchronization is called cooperative synchronization . This chapter explains what cooperative synchronization is and why it is important, as well as some of the pitfalls that can occur when implementing it.
The animator presented in Chapter 7 is used to
A number of the same problems
|
|
< Day Day Up > |
|
|
|
< Day Day Up > |
|
After completing this chapter, you should know the following:
The difference between cooperative synchronization and competitive synchronization
What can happen if threads are not coordinated and how to use the synchronization with wait and notify
Why it is invalid to use sleep times to achieve cooperative synchronization
How to protect against race conditions when using the animator to move an object in a thread
What is a notification object and how it can be implemented
|
|
< Day Day Up > |
|
|
|
< Day Day Up > |
|
Synchronization is used in a program for two reasons: allow threads to
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
Exhibit 1: Program8.1: Thread Animation with No Coordination
|
|
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); } }
|
|
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;
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
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 > |
|