Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the necessity of wait() and notify() [duplicate]

I have tried to understand the necessity to implement threads by using wait() and notify() when accessing shared resources or relying on their state.

I see that the idea is to monitor objects and to wait for their availability and releasing them after use to make them usable for other threads/methods, but why are those methods necessary instead of just declaring the relevant objects as static volatile so that other threads learn about the change of state without invoking those methods?

For example

In a restaurant, there are 2 chefs. One of the chefs is a good chef (better cooking qualities, ..) and carries a boolean isGoodCook = true, while the second chef is a bad chef and carries a boolean isGoodCook = false.

There is only equipment for one chef to cook meals at a time. The bad chef cooks for a specific amount of time (= cookingTime) while the good chef comes into the kitchen occasionally to take over the bad chef's task of cooking meals. The good chef can never be interrupted in his cooking process and cooks for his entire cookingTime once he started.

(Bad chef stops cooking as long as the good chef takes the part of cooking meals (= cookingTime of good chef)).

And after the good chef stops cooking meals, the bad chef has to carry on the task of preparing meals once again.

private boolean cooking; //is equipment used at the moment
private boolean isGoodCook;
private boolean cookingDesire; //indicating to chef to stop cooking
private int cookingTime;


public CookingTask(boolean isGoodCook, int cookingTime)
{
    this.isGoodCook = isGoodCook;
    this.cookingTime = cookingTime;
}

public void run()
{  
    if(isGoodCook)
    {
        //notify actual cook to stop cooking
        cookingDesire = true; 
    }
    //wait til equipment to cook
    //is available
    while(cooking)
    {
        try 
        {
            wait();
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }
    //reserve equipment
    cooking = true;
    cookingDesire = false;
    //notify other threads (= bad cook)
    notifyAll();
    startCooking();
}

private void startCooking()
{
    for(int i = 0; i < cookingTime; cookingTime--)
    {
        try 
        {
            Thread.sleep(1000);
            //if good chef comes in
            if(cookingDesire)
            {
                //bad chef starts to pause
                startBreak();
            }
        }
        catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }
    cooking = false;
}

public void startBreak()
{
    //bad chef stops cooking
    cooking = false;
    notifyAll();
    //measure break time of bad chef
    long stopCookingTime = System.currentTimeMillis();
    while(cookingTime > 0 && cooking)
    {
        try 
        {
            wait();
        } catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
    }
    int pausedTime = toIntExact((System.currentTimeMillis() - stopCookingTime)/1000);
    //calculate remaining cookingTime
    cookingTime -= pausedTime;
    cooking = true;
    notifyAll();
}

Maybe someone has the time to read through and shortly outline my misconceptions on monitoring/wait() and notify() on multiple threads, I'd gladly appreciate it!

like image 868
freeprogramer233 Avatar asked Mar 12 '16 12:03

freeprogramer233


2 Answers

static means that all objects of a class share that data. How do you think a static field could thus be used to say anything about the status of a specific thread object?

I guess one could get rid of wait/notify; in a way that one thread has to query properties of other threads. But that means "activity": that "waiting" thread has to do polling. Of course, you can't be polling constantly, so you would want it to sleep for certain periods of time. Which is ... almost as waiting, but more complicated, because you have to manage all the subtle details by writing code.

With wait/notify you have a push model. If a thread needs to wait; you tell it to do so; and then, when time comes, it will be woken up. That is a pretty clear, straight forward semantic.

So, when you propose a different model to solve that problem; you would really have to prove that your model achieves the same goal; and beyond that, figure additional benefits of that model.

like image 162
GhostCat Avatar answered Sep 23 '22 09:09

GhostCat


declaring the relevant objects as static volatile so that other threads learn about the change of state without invoking those methods?

Purpose of static and volatile is completely different from the wait-notify mechanism provided by threads when the state changes or condition is met.

Static - Indicates a field/method is associated at the class rather than instance level and doesn't need an object to be created to use them.

Volatile - Instructs the JVM to always read the latest value of this field, i.e., guarantees visibility of changes to volatile variables across threads and avoids cache coherency issues.

Coming to wait and notify, it is a communication mechanism employed by threads and we will see it from a producer-consumer example.

Producer places the tasks to into queue that needs to be consumed/completed by Consumer.

Start with scenario where a consumer is waiting for a task to appear in the queue (empty queue). Producer puts the tasks and subsequently it notifies any waiting consumer. This wakes up the consumer and it starts processing the tasks. Without that consumer has to keep polling the queue for the task.

From a producer end, it keeps on putting the tasks in the queue untill the queue is full and subsequently producer waits till the space becomes available in the queue. The consumer as it picks up the task and makes some free space in the queue can notify the producer. Without this producer has to poll the queue periodically for free space.

So wait-notify are communication mechanisms that threads use to communicate among themselves of any condition/state changes.

Also with wait and notify, JMM provides memory visibility guarantee with happens before relationship.

On a similar note, JMM guarantees a write to a volatile field happens-before every subsequent read of that field but don't confuse with the wait-notify mechanism provided by threads.

Below is an image from Java revisited link that shows producer-consumer pattern using wait notify. Green dashed lines invoking the notify methods to wake up the waiting threads when the condition is met. You may want to go through the link if interested in the related code.

Java wait-notify with Producer consumer pattern

like image 24
Madhusudana Reddy Sunnapu Avatar answered Sep 23 '22 09:09

Madhusudana Reddy Sunnapu