Scala notify () vs notifyAll ()

Given the following implementation of a consumer-producer problem in scala

class PC { var buffer = null.asInstanceOf[Int] var set = false def produce(value: Int) = synchronized { while (set) wait() buffer = value set = true notify() } def consume: Int = synchronized { while (!set) wait() val result = buffer set = false notify() return result; } } 

There are 3 things that I can’t see:

  • Why, if I use notification instead of notifyAll, I find myself at a dead end; Where should I use notifyAll, for production or consumption?

  • Should I have an object, for example. blocking and blocking calls. synchronized, lock.wait and lock.notify? Why does it work like this, do not produce and do not consume, do they have 2 different monitors? Why "notify" from a product notifies "wait" from consumption?

  • How does the monitor work in scala (in our case)? Does it use a signal-and-continue policy? How do processes from a wait queue in a certain state move to an execution queue? Is there a queue for each condition / lock (e.g. lock1.wait, lock2.wait, etc.).

+6
source share
2 answers

This is really a question mainly about Java concurrency. Scala concurrency is built on top of the Java concurrency model, but the syntax is different. In Scala, synchronized is the AnyRef method , and the above syntax is equivalent to using the synchronized to write synchronized methods, as in the following Java code:

 public class PC { public int buffer; public boolean set; public synchronized void produce(int value) { while(set) wait(); buffer = value; set = true; notify(); } public synchronized int def consume { while(!set) wait(); int result = buffer; notify(); return result; } } 

For a more detailed description of the Java concurrency model, check out the Java Tutorials . You can learn the Java concurrency Library . For example, you can implement the same thing using the Blocking Queue with a capacity of 1.

Answering your questions:

1. Why, if I use notification instead of notifyAll, I find myself at a dead end; Where should I use notifyAll, for production or consumption?

You probably have a race condition (not a dead end), because notify() in consumer() received by some other consumer stream, not the producer stream, but this is just an assumption. Regarding the use of notify() or notifyAll() and in which methods some recommend using notifyAll() . And in this case, you can use notifyAll() , because you expect in the conditional while loop, which you should always execute for various reasons described in the documentation to wait () . However, you can also use notify() as an optimization in producer() , because I assume that you want one consumer to consume the contents of the buffer. With the current implementation, you should still use notifyAll() in consume() or potentially expose yourself to a situation where one of the consumers is notified, and not the only provider of expectations, as a result of which the producer waits forever.

2. If I do not have an object, for example. blocking and blocking calls. synchronized, lock.wait and lock.notify? Why does it work like this, do not produce and do not consume, do they have 2 different monitors? Why does a “notification” from a product notify “wait” from consumption?

You have a lock. This is an implicit lock on the PC instance, and in Java there is one and only one monitor per object, although there may be many entry points. wait() in consume() notified of notify notify() in produce() , because they both wait for a lock on the same resource - an instance of the PC . If you want to implement a more flexible or fine-grained locking, you can use various strategies from the Java concurrency Library , for example Locks .

3. How does the monitor work exactly in Scala (in our case)? Does it use a signal-and-continue policy? How do processes from a wait queue in a certain state move to an execution queue? Is there a queue for each condition / lock (e.g. lock1.wait, lock2.wait, etc.).

For a good description of how the JVM synchronizes threads, read the following: How the Java Virtual Machine synchronizes threads . For more information from the chapter of the same author, you can read Inside the Java Virtual Machine .

+5
source

Why, if I use notification instead of notifyAll, do I get stuck?

As you may have noticed, the problem you are observing does not occur if there is only one producer and one consumer (because in this case notify performs the task that you expect from him, which should allow the next producer / consumer to make their move )

If you have more than one manufacturer or consumer, the following problem arises: let's say there are 2 manufacturers and one consumer. In this case, if you use notify() :

  • One of the producers works and calls notify()
  • Instead of the consumer, another manufacturer is notified
  • The producer awakened by notify() now waits indefinitely because the consumer will never receive a notification

If notifyAll is called notifyAll , the consumer will always be notified, so the problem that the producer or consumer waits endlessly for the other side never arises.

If I don't have an object, for example. blocking and blocking calls. synchronized, lock.wait and lock.notify?

The lock object is a PC object. A Scala object is just one instance of a class that the compiler generates for you. Since your object is actually an instance of a class of the object class, it also inherits the notify , notifyAll and wait methods.

+1
source

All Articles