THE UNIVERSITY OF WESTERN AUSTRALIA

School of Computer Science & Software Engineering

CITS3211 CONCURRENT SYSTEMS PART II

Laboratory Sheet 2 (not assessed)

The purpose of this laboratory is to :

Synchronizing Threads

Till now, our threads mostly have executed at their own will or, rather at the will of the scheduler. However, as you have seen in the lectures, you may need to coordinate the access of multiple threads to shared objects in your program. Java allows you to coordinate the actions of multiple threads using synchronized methods and synchronized statements. Here is how it is done.

The synchronized methods are declared with the synchronized keyword. Only one synchronized method can be invoked for an object at a given point. This prevents synchronized methods from multiple objects from conflicting with each other.

All classes and objects are associated with a unique monitor. The monitor associated with an object is used to control the way in which synchronized methods access the class or object. When a synchronized method is invoked for an object, it is said to acquire the monitor for that object. No other synchronized method can be invoked for that object until the monitor is released. A monitor is automatically released when the execution of the method is complete or when the synchronized method executes a method like wait(). In the second case, the thread associated with the currently executing synchronized method becomes not runnable until the wait condition is satisfied and no other method has acquired the object's monitor.

Here is an example program for synchronizing the execution of two threads. This is based on the Example1.java program in lab1. Here is some explanation of the program.

Java Concurrency Constructs

The following are the concurrency constructs and support in the Java language. Though this list is quite small, it is possible to write a wide range of concurrent programs with these constructs.

Waiting and Notification

Tasks

Synchronization and Deadlock

[AN ADDITIONAL EXERCISE ON SYNCHRONIZATION AND DEADLOCKS APPEARS BELOW.]

The file Account.java contains a simple multithreaded program involving two bank accounts, with a thread for each account that repeatedly transfers money to the other account. This code is unsynchronized, and it also allows bank balances to go negative.

Tasks

Take a copy of the Account.java file, and add appropriate synchronization. Also, a thread performing a transfer should wait if the account balance is less than the transfer amount. (Hint: call notifyAll in an appropriate place to wake a waiting thread.)

Try running your program. What happens? Add appropriate print statements to figure out exactly how far your program continues to run. Most likely, your program will deadlock at a certain point unless you have been very careful to avoid deadlocks.

Consider how you could fix your program to avoid deadlocks. There are a number of different ways, although they all require some reorganization of the code. (Hint: one of the easier approaches is to arrange things so that both threads always acquire locks in the same order.) You may find it useful to use a synchronized statement like the following.

 
     public void method() {
          // Some code ...

          synchronized (object) {
              // Code run while holding the lock for "object"
          }
          // Some more code...
     }
This allows you take any statement in your program and specify that it must hold the lock on a particular object while it is running. See the Java Tutorial for more details.

April, 2008.