Thread Synchronisation
Operating Systems Lab Class 5
In this lab session we will look at the problem of synchronising the access of multiple reader and writer threads to a shared data record. You will learn how to use synchronized, wait and notify to solve this problem.
1 Thread Synchronisation
If multiple threads need to use the same objects or static class variables concurrently, thread access to shared data must be carefully managed. Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object’s fields has to acquire the object’s intrinsic lock before accessing them, and then release the intrinsic lock when it’s done with them.
The Java synchronized keyword
The Java synchronized keyword is an essential tool in concurrent programming in Java. Its overall purpose is to only allow one thread at a time into a particular section of code thus allowing us to protect, for example, variables or data from being corrupted by simultaneous modifications from different threads. When a thread acquires a lock of an object either for reading or writing, other threads must wait until the lock on that object is released, see Figure 1.
Figure 1: Mutual exclusion of critical section
Multiple Readers and Writers
The readers-writers problems are examples of a common computing prob- lem in concurrency. For example, making an airline reservation: when you browse to look at flight schedules the web site is acting as a reader on your behalf, and when you reserve a seat, the web site has to write into the database to make the reservation. As a basic solution for this problem, you want to allow multiple readers, but you do not want a reader and a writer to overlap, as this could result in the reader reading inconsistent data.
1
We are going to write a program in which multiple reader and writer threads have to coordinate their reading and updating of a shared data record in order to avoid inconsistencies.
1.1 Getting Started
1. Download the os-lab5.zip archive from Canvas and unzip it into your workspace.
2. Start NetBeans and open the project. The project should contain four files in the src directory:
Database.java (contains the main method), Record.java, ReaderTask.java and WriterTask.java. 3. Compile and run the code. This should work without problems.
1.2 Implementation 1
4. The program will work as follows:
• Step 1: The input arguments should have this sequence: [number Readers, Writer1, Writer2,…]
The program takes the number of readers and any number of records, each consisting of three argu- ments: first name, last name, address. E.g. running with three readers and two writers such as java Database 3 Joe Q Brighton Mary L London should output
writer 0: Joe Q Brighton
reader 2: Joe Q Brighton
reader 1: Joe Q Brighton
writer 1: Mary L London
reader 0: Mary L London
• Step 2: Create the shared database record.
• Step 3: Complete Database.java to parse the command line arguments and create the threads for
writers and readers, i.e. running WriterTask and ReaderTask. – Constructor for objects of class WriterTask:
WriterTask(int writerId,Record record,String firstName,String lastName,String address)
– Constructor for objects of class ReaderTask: ReaderTask(int readerId, Record record)
1.3 Reflection
5. Run this program several times with different numbers of readers and writers and observe its output. What do you observe? Explain what is happening and why.
1.4 Implementation 2
6. Complete now the remaining classes:
• Step 4: Record class has the following methods to be used by the Writer threads:
– updateFirstName(firstName) , updateLastName(lastName) , updateAddress(address) and the following methods to be used by the Reader threads:
– readFirstName() , readLastName() , readAddress()
• Step 5: Fill in the gaps in Record.java in order to ensure the correct behaviour of “simultaneous” readers and writers. You find hints about the possible algorithm in the comment blocks of the locking functions. Mainly, you are asked to complete the following methods,
– acquireReadLock() – releaseReadLock() – acquireWriteLock() – releaseWriteLock()
Your implementation will require the use of the wait() and notify() (respectively notifyAll()) methods as defined in the java.lang.Object class. Look at the Java API to understand what they are doing. Also read about synchronized methods.
• Step 6: update the run() method in both WriterTask and ReaderTask by acquiring and releasing write/read lock (i.e. you need to call the four methods that you have completed in Step 5).
• Step 7: Test your program with different numbers of readers and writers.
7. Extra question: Is it possible to ensure the correct behaviour using synchronized only? Implement and
try your solution. What are its disadvantages?
2 Java API References
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html
http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html