Understanding the need for wait () and notification ()

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

I see that the idea is to control the objects and wait for their availability and release them after use to make them suitable for use by other threads / methods, but why do we need these methods, and not just declare the corresponding objects as static volatiles, that others Do threads know about a state change without calling these methods?

for example

The restaurant has 2 chefs. One of the chefs is a good chef (best culinary 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 dishes at a time. A bad chef cooks for a certain time (= cookingTime), while a good chef comes to the kitchen to take on the job of a bad chef cooking. A good chef should never be interrupted in the cooking process and cooked for all his culinary time as soon as he started.

(The bad chef stops cooking while the good chef accepts some of the cooking (= cookingTime of the good chef)).

And after the good chef stops cooking, the bad chef must again complete the cooking task.

 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 time to read and briefly outline my misconceptions about monitoring / wait() and notify() on multiple threads, I would gladly appreciate it!

+7
java multithreading
source share
4 answers

static means that all objects in the class use this data. Why do you think a static field could be used to say something about the status of a particular stream object?

I think one could get rid of wait / notify; so one thread must request the properties of the other threads. But that means “activity”: this “waiting” thread should do the polling. Of course, you cannot constantly conduct a survey, so you want it to sleep for certain periods of time. Which ... almost as expected, but more complex because you need to manage all the subtle details by writing code.

With pending / notification, you have a push model. If the thread must wait; you tell him to do it; and then when the time comes, he will wake up. This is pretty clear, straightforward semantics.

So, when you propose another model to solve this problem; you really need to prove that your model is achieving the same goal; and also indicate the additional benefits of this model.

+4
source share

declaring relevant objects as static volatile so that other threads know about the state change without calling these methods?

The goal of static and volatile is completely different from the wait expectation mechanism provided by threads when a state changes or a condition is met.

Static - indicates that the field / method is associated with the class, not the instance level, and does not need to create an object to use them.

Volatile - instructs the JVM to always read the last value of this field, that is, it guarantees the visibility of changes in variable variables in all threads and avoids problems with cache coherency.

Waiting and notifying, this is the communication mechanism used by threads, and we will see it from the example of the producer-consumer.

The producer queues tasks that should be consumed / performed by the user.

Start with a scenario in which the consumer expects the task to appear in the queue (empty queue). The manufacturer sets tasks and then notifies any expecting consumer. This awakens the consumer and begins processing tasks. Without this, the consumer must continue to poll the queue for the task.

From the end of the producer, he continues to queue the tasks until the queue is full, and then the producer waits until the space becomes available in the queue. The consumer as he raises the task and makes some free space in the queue, can notify the manufacturer. Without this producer, you periodically need to periodically check the queue for free space.

Thus, wait-notify are communication mechanisms that use threads to communicate with each other for any state / state changes.

In addition, with waiting and notification, JMM provides a guarantee of memory visibility that occurs before the relationship.

Similarly, JMM guarantees writing to the volatile field - before each subsequent reading of this field, but do not confuse it with the wait-notify mechanism provided by threads.

Below is the image of the Java revisited link , which displays the producer-consumer pattern using wait wait. Green dashed lines that call notification methods to wake pending threads when the condition is met. You can follow the link if you are interested in the corresponding code.

Java wait-notify with sample producer Producer

+3
source share

Since both are for different purposes, let's understand the main differences.

static : one copy of the variable for all objects.

volatile : get variable value from main memory instead of thread cache

In many applications, copying an object rather than a single copy is required for all objects. You should not limit yourself to using a copy of the class for a multi-threaded application with static volatile , if your suggestion is a way to access a multi-threaded application.

Now let's move on to the unstable variable in the absence of static . Getting the last value from main memory is great. But if multiple threads change the value, you cannot guarantee consistency.

Take an example of your bank account. Suppose your account balance is $ 50. One thread adds the value from the deposit() method. Another thread subtracts the value from the withdrawal() method.

Thread 1 : Received balance value as $ 50 from main memory instead of cache. The deposit happened with 25 dollars, and the balance now is 75. Suppose that the deposit is not synchronized, and there is no wait () and notify ().

 public void deposit(){ //get balance : 50 // update : 75 // print : 25 ( if withdrawal completes before print statement and after get balance statement } 

Thread 2 : Received balance value as $ 50 from main memory instead of cache. The withdrawal occurred for $ 25, and the balance is now 25.

 public void withdrawal(){ //get balance : 50 // update : 25 // print : 25 } 

Just make variable , because volatile doesn't help. You must synchronize data for consistency.

See below SE questions to better understand the concepts:

Difference between mutable and synchronized in Java

Flying Vs Static in java

Static variable vs Volatile

+1
source share

You can use locks and / or mutable variables to perform synchronization tasks that “wait” and “notify” are designed to be executed, but this will be inefficient. As a simple example of the intended use, consider a message queue and a thread whose task is to read messages and process them. If the thread does not process the message and the queue is empty, nothing can be useful for the thread.

It would be possible to have a message processing thread that simply acquired a lock, checked if the queue was empty, and if the lock was not briefly released, then acquired it again, checked again if the queue was empty, etc. but such a stream would require the processor to spend a huge amount of time checking the empty queue for waiting messages, when perhaps something is even more useful when the processor could do it.

The easiest way to think about “waiting” is to offer an indication to the Java virtual machine that the thread has determined that there will be nothing useful for it, unless someone points out through a “notification” that something interesting could happen . The JVM is not required to do anything with this indication, but in most cases this will prevent the thread that is “waiting” from getting more processor time until the object it is waiting for receives a “notification”. A thread can receive processor time even before that (for example, a JVM running in a small embedded system may not bother tracking what object streams expect, but may legitimately “wait”, pause the thread until the next “notification” passed to any object], but with a thread that the processor receives unnecessarily several times unnecessarily, briefly before it is really needed, it will be much worse than a stream that unnecessarily receives processor time continuously.

+1
source share

All Articles