Friday, February 25, 2011

Chapter 61: Thread Interactions

The last thing we need to look at in our series of chapters on threads, is how threads can interact with one another to communicate about, among other things, their locking status. The Object class has three methods, wait(), notify(), and notifyAll() that help threads communicate about the status of an event that the threads care about.


This is exactly what we are going to see in this chapter.


So, lets get started!!!


Using Wait and Notify


For example, if one thread is a repair-car repair-car thread and one thread is a accept-car-for-service thread, the accept-car-for-service thread has to keep checking to see if there’s any car to accept for service. Using the wait and notify mechanism, the accept-car-for-service thread could check for cars, and if it doesn’t find any it can say, “Hey, I’m not going to waste my time checking for a car every few minutes. I’m going to go hang out, and when a customer drives in with a car for service, have him notify me so I can go back to runnable and do some work.” In other words, using wait() and notify() lets one thread put itself into a “waiting room” until some other thread notifies it that there’s a reason to come back out.


One key point to remember for the exam about wait/notify is this:


wait(), notify(), and notifyAll() must be called from within a synchronized context! A thread can’t invoke a wait or notify method on an object unless it owns that object’s lock.


Here we’ll present an example of two threads that depend on each other to proceed with their execution, and we’ll show how to use wait() and notify() to make them interact safely and at the proper moment.


Think of a computer-controlled Mechanic that repairs cars and the user comes to the garage to drop of his car to repair. The current version of the application has one thread, which loops, first getting the car from the user and then giving it to the mechanic for repair:


public void run(){

while(true){

// Get Car from user

// Analyse and identify faulty parts

// Fix em...

// Send user home happy...

}

}


This design is not optimal because the user can’t do anything while the mechanic is busy and while there are other parts to fix. We need to improve the situation.


A simple solution is to separate the processes into two different threads, one of them interacting with the user and another fixing the car. The user thread sends the instructions to the fixing thread and then goes back to interacting with the user immediately. The fixing thread receives the instructions from the user thread and starts directing the mechanic immediately. Both threads use a common object to communicate, which holds the current car being processed.
The following pseudocode shows this design:


public void keepUserEngagedLoop(){

while(true){

// Get car from user

// Pass car repair instructions to fixing thread

}

}


public void fixingLoop(){

while(true){

// Get car into garage

// start fixing it

}

}


The problem now is to get the fixing thread to process the car as soon as it is available. Also, the user thread should not disturb the car until it is sent to the garage. The solution is to use wait() and notify(), and also to synchronize some of the code.


The methods wait() and notify(), remember, are instance methods of Object. In the same way that every object has a lock, every object can have a list of threads that are waiting for a notification from the object. A thread gets on this waiting list by executing the wait() method of the target object. From that moment, it doesn’t execute any further instructions until the notify() method of the target object is called. If many threads are waiting on the same object, only one will be chosen (in no guaranteed order) to proceed with its execution. If there are no threads waiting, then no particular action is taken. Let’s take a look at some real code that shows one object waiting for another object to notify it:


1. class FirstThread {

2. public static void main(String [] args) {

3. SecondThread b = new SecondThread();

4. b.start();

5.

6. synchronized(b) {

7. try {

8. System.out.println("Waiting for b to complete...");

9. b.wait();

10. } catch (InterruptedException e) {}

11. System.out.println("Value is: " + b.value);

12. }

13. }

14. }

15.

16. class SecondThread extends Thread {

17. int value;

18.

19. public void run() {

20. synchronized(this) {

21. for(int i=0;i<10;i++) {

22. value += i;

23. }

24. notify();

25. }

26. }

27. }



This program contains two objects with threads: FirstThread contains the main thread and SecondThread has a thread that calculates the sum of all numbers from 0 through 9. As soon as line 4 calls the start() method, FirstThread will continue with the next line of code in its own class, which means it could get to line 11 before SecondThread has finished the calculation. To prevent this, we use the wait() method in line 9.


Notice in line 6 the code synchronizes itself with the object b, this is because in order to call wait() on the object, FirstThread must own a lock on b. For a thread to call wait() or notify(), the thread has to be the owner of the lock for that object. When the thread waits, it temporarily releases the lock for other threads to use, but it will need it again to continue execution. It’s common to find code like this:


synchronized(someObject) { // this has the lock on someObject

try {

someObject.wait();

// the thread releases the lock and waits

// To continue, the thread needs the lock,

// so it may be blocked until it gets it.

} catch(InterruptedException e){}

}



The preceding code waits until notify() is called on someObject.

synchronized(this) { notify(); }



This code notifies a single thread currently waiting on the this object. The lock can be acquired much earlier in the code, such as in the calling method. Note that if the thread calling wait() does not own the lock, it will throw an IllegalMonitorStateException. This exception is not a checked exception, so you don’t have to catch it explicitly. You should always be clear whether a thread has the lock of an object in any given block of code.

Notice in lines 7–10 there is a try/catch block around the wait() method. A waiting thread can be interrupted in the same way as a sleeping thread, so you have to take care of the exception:


try {

wait();

} catch(InterruptedException e) {

// Do something about it

}


In the car garage example, the way to use these methods is to have the fixing thread wait on the car to be available and the user thread to notify after it has finished giving the car. The fixing steps may comprise global steps, such as moving the car to the garage area, and a number of substeps, such as checking the engine, transmission. As an example they could be


int NumberOfCylindersInEngine;

int NumberOfGearsInTransmission;

Engine engineMake;

float[] tires;

etc..


It is important that the user thread does not modify the car details while the fixing thread is using them, so this reading and writing should be synchronized.


The resulting code would look like this:

class User extends Thread {

public void run(){

while(true){

// Get car from user

synchronized(this){

// identify details to fix the car

notify();

}

}

}

}


class Mechanic extends Thread {

User User; // assume this gets initialized

public void run(){

while(true){

synchronized(User){

try {

User.wait();

} catch(InterruptedException ie) {}

// Send Mechanic steps to fixing

}

}

}

}


The Mechanic thread, once started, will immediately go into the waiting state and will wait patiently until the User sends the first notification. At that point it is the User thread that owns the lock for the object, so the fixing thread gets stuck for a while. It’s only after the User thread abandons the synchronized block that the fixing thread can really start processing the Mechanic steps.


While one car is being processed by the mechanic, the user may interact with the system and specify another car to be serviced. When the user is finished with the car and it is time to repair it, the User thread attempts to enter the synchronized block, maybe blocking until the Mechanic thread has finished with the previous Mechanic steps. When the Mechanic thread has finished, it repeats the loop, going again to the waiting state (and therefore releasing the lock). Only then can the User thread enter the synchronized block and overwrite the Mechanic steps with the new ones.


Having two threads is definitely an improvement over having one, although in this implementation there is still a possibility of making the user wait. A further improvement would be to have many cars in a queue, thereby reducing the possibility of requiring the user to wait for the mechanic.


There is also a second form of wait() that accepts a number of milliseconds as a maximum time to wait. If the thread is not interrupted, it will continue normally whenever it is notified or the specified timeout has elapsed. This normal continuation consists of getting out of the waiting state, but to continue execution it will have to get the lock for the object:


synchronized(a){ // The thread gets the lock on 'a'

a.wait(5000); // Thread releases the lock and waits for notify

// only for a maximum of five seconds, then goes back to Runnable

// The thread reacquires the lock

// More code here

}


Exam Tip:
When the wait() method is invoked on an object, the thread executing that code gives up its lock on the object immediately. However, when notify() is called, that doesn’t mean the thread gives up its lock at that moment. If the thread is still completing synchronized code, the lock is not released until the thread moves out of synchronized code. So just because notify() is called doesn’t mean the lock becomes available at that moment
Using notifyAll( )

In most scenarios, it’s preferable to notify all of the threads that are waiting on a particular object. If so, you can use notifyAll() on the object to let all the threads come out of the waiting area and back to runnable. This is especially important if you have several threads waiting on one object, but for different reasons, and you want to be sure that the right thread (along with all of the others) gets notified.


notifyAll(); // Will notify all waiting threads


All of the threads will be notified and start competing to get the lock. As the lock is used and released by each thread, all of them will get into action without a need for further notification.


As we said earlier, an object can have many threads waiting on it, and using notify() will affect only one of them. Which one, exactly, is not specified and depends on the JVM implementation, so you should never rely on a particular thread being notified in preference to other threads.


In cases in which there might be a lot more waiting, the best way to do this is by using notifyAll(). Let’s take a look at this in some code. In this example, there is one class that figures out a stocks current price and many stock traders that are waiting to receive the current value. At any given moment many traders may be waiting.


1. class Trader extends Thread {

2. StockPriceAnalyzer c;

3.

4. public Trader(StockPriceAnalyzer calc) {

5. c = calc;

6. }

7.

8. public void run() {

9. synchronized(c) {

10. try {

11. System.out.println("Waiting for calculation...");

12. c.wait();

13. } catch (InterruptedException e) {}

14. System.out.println("Value is: " + c.value);

15. }

16. }

17.

18. public static void main(String [] args) {

19. StockPriceAnalyzer StockPriceAnalyzer = new StockPriceAnalyzer();

20. new Trader(StockPriceAnalyzer).start();

21. new Trader(StockPriceAnalyzer).start();

22. new Trader(StockPriceAnalyzer).start();

23. StockPriceAnalyzer.start();

24. }

25. }

26.

27. class StockPriceAnalyzer extends Thread {

28. int value;

29.

30. public void run() {

31. synchronized(this) {

32. for(int i=0;i<10;i++) {

33. value += i;

34. }

35. notifyAll();

36. }

37. }

38. }


The program starts three threads that are all waiting to receive the finished calculation (lines 18–24), and then starts the StockPriceAnalyzer with its calculation. Note that if the run() method at line 30 used notify() instead of notifyAll(), only one Trader would be notified instead of all the Traders.


Apologies for the crappy code inside the stock market prize analyzer class. I cant probably put code that calculates the current price of any share in such a small place. So I just put in some code that does addition in a loop. As long as you understand the concept and not curse me for the example I am good!!!


Using wait( ) in a Loop


Actually both of the previous examples (Mechanic/User and Trader/StockPriceAnalyzer) had a common problem. In each one, there was at least one thread calling wait(), and another thread calling notify() or notifyAll(). This works well enough as long as the waiting threads have actually started waiting before the other thread executes the notify() or notifyAll(). But what happens if, for example, the StockPriceAnalyzer runs first and calls notify() before the Traders have started waiting? This could happen, since we can’t guarantee what order the different parts of the thread will execute in. Unfortunately, when the Traders run, they just start waiting right away. They don’t do anything to see if the event they’re waiting for has already happened. So if the StockPriceAnalyzer has already called notifyAll(), it’s not going to call notifyAll() again—and the waiting Traders will keep waiting forever. This is probably not what the programmer wanted to happen. Almost always, when you want to wait for something, you also need to be able to check if it has already happened. Generally the best way to solve this is to put in some sort of loop that checks on some sort of conditional expressions, and only waits if the thing you’re waiting for has not yet happened. Here’s a modified, safer version of the earlier Car & Mechanic example:


class User extends Thread {

Mechanic Mechanic; // assume this gets initialized

public void run() {

while (true) {

Car car = getCarFromUser();

MechanicInstructions job = processCarForInstructions(shape);

Mechanic.addCarForRepair(job);

}

}

}



The User will still keep on looping forever, getting more cars from users, calculating new instructions for those cars, and sending them to the Mechanic. But now the logic for notify() has been moved into the addCarForRepair() method in the Mechanic class:


class Mechanic extends Thread {

List jobs = new ArrayList();

public void addCarForRepair(MechanicInstructions job) {

synchronized (jobs) {

jobs.add(job);

jobs.notify();

}

}

public void run() {

while (true) {

synchronized (jobs) {

// wait until at least one car is available

while (jobs.isEmpty()) {

try {

jobs.wait();

} catch (InterruptedException ie) { }

}

// If we get here, we know that jobs is not empty

MechanicInstructions instructions = jobs.remove(0);

// Send Mechanic steps to garage

}

}

}

}


A Mechanic keeps a list of the jobs it’s scheduled to do. Whenever an User adds a new job to the list, it calls the addCarForRepair() method and adds the new job to the list. Meanwhile the run() method just keeps looping, looking for any jobs on the list. If there are no jobs, it will start waiting. If it’s notified, it will stop waiting and then recheck the loop condition: is the list still empty? In practice this double-check is probably not necessary, as the only time a notify() is ever sent is when a new job has been added to the list. However, it’s a good idea to require the thread to recheck the isEmpty() condition whenever it’s been woken up, because it’s possible that a thread has accidentally sent an extra notify() that was not intended.


There’s also a possible situation called spontaneous wakeup that may exist in some situations; a thread may wake up even though no code has called notify() or notifyAll().What this means is, when your thread wakes up from a wait(), you don’t know for sure why it was woken up. By putting the wait() method in a while loop and re-checking the condition that represents what we were waiting for, we ensure that whatever the reason we woke up, we will re-enter the wait() if and only if the thing we were waiting for has not happened yet. In the Mechanic class, the thing we were waiting for is for the jobs list to not be empty. If it’s empty, we wait, and if it’s not, we don’t.


Note also that both the run() method and the addCarForRepair() method synchronize on the same object, the jobs list. This is for two reasons. One is because we’re calling wait() and notify() on this instance, so we need to synchronize in order to avoid an IllegalThreadState exception. The other reason is, the data in the jobs list is changeable data stored in a field that is accessed by two different threads. We need to synchronize in order to access that changeable data safely. Fortunately, the same synchronized blocks that allow us to wait() and notify() also provide the required thread safety for our other access to changeable data. In fact this is a main reason why synchronization is required to use wait() and notify() in the first place, you almost always need to share some mutable data between threads at the same time, and that means you need synchronization. Notice that the synchronized block in addCarForRepair() is big enough to also include the call to jobs.add(job,)which modifies shared data. And the synchronized block in run() is large enough to include the whole while loop—which includes the call to jobs.isEmpty(), which accesses shared data.


The moral of the story here is (again value education stuff) that when you use wait() and notify() or notifyAll(), you should almost always also have a while loop around the wait() that checks a condition and forces continued waiting until the condition is met. And you should also make use of the required synchronization for the wait() and notify() calls, to also protect whatever other data you’re sharing between threads. If you see code which fails to do this, there’s usually something wrong with the code, even if you have a hard time seeing what exactly the problem is.


Exam Tip:
The methods wait() , notify(), and notifyAll() are methods of only java.lang.Object, not of java.lang.Thread or java.lang.Runnable. Be sure you know which methods are defined in Thread, which in Object, and which in Runnable (just run(), so that’s an easy one). Of the key methods in Thread, be sure you know which are static—sleep() and yield(), and which are not static—join() and start()

Key Thread Methods

To wrap up this chapter, we will take a look at the important thread methods and then we will call it a day!!!


Methods in the Object Class:
a. wait()

b. notify()

c. notifyAll()



Methods in the Thread Class:
a. start()

b. yield()

c. sleep()

d. join



Methods in the Runnable Interface:
a. run()


That's it folks. We are done with Threads!!! Ugh, that was pretty long and hard. Wasn't it? :-)

Previous Chapter: Chapter 60 - Synchronization

Next Chapter: Quick Review - Threads

2 comments:

  1. In my opinion wait/notify is best way for inter thread communication but keep in mind if you have more than two threads its always better to use notifyAll(), Its also good to know How to find if a thread holds lock on a particular object in Java .

    On a related note incorrect written multi threaded programs often results in deadlock specially if number of shared resources are more and number of accessing threads are also high its worth knowing How to find and fix deadlock in Java ?

    Thanks
    Javin

    ReplyDelete
  2. Thanks for the article. Very detailed and well written.

    ReplyDelete

© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers