Search code examples
javamultithreadingconcurrencysynchronized

Java concurrency, connection between wait and notify, deadlocks


I am new to basic concurrency in Java. As far as I understood, it is possible to have several threads inside a synchronized block if only one of them is active and the other ones are waiting. As I am learning with a book on java, I was trying to solve an exercise concerning the reader-writer-problem with 3readers that are supposed to read the numbers, and 3 writers how print out the numbers from 0 to 4 and then end. The main class, writer class and reader class (see below) were given. The official solution that my book gives is this ("Erzeuger" is supposed to be "writer", "Verbraucher" is supposed to be "reader", "Wert" is the value that is set): main class value class writer class reader class

But would I not run into a deadlock if at the beginning all readers go into the waiting state of the get Method because there is no value available yet and the "verfuegbar" flag is false. Then a value could be created by one of the writers and one reader could get woken up by notify, then all three writers could go into the waiting state of the put method, then the reader could read the value, then another reader could get woken up and so they all land inside of the waiting method and it is a deadlock?

What am I missing here, or is the book's solution wrong? Thanks in advance!


Solution

  • The "deadlock" that you described has another name: "Lost notification."

    In order to use wait/notify correctly, you need an explicit, testable condition, and you need to follow this pattern:

    Consumer:

    synchronized (lock) {
        while (condition_is_not_true()) {
            lock.wait();
        }
        do_something_that_requires_condition_to_be_true();
        maybe_make_it_false_again_maybe_not_thats_up_to_you();
    }
    

    Producer:

    synchronized (lock) {
        make_the_condition_true();
        lock.notify();
    }
    

    Two rules are embodied here:

    1. Nobody changes the state of the explicit condition unless they are holding the lock, and

    2. The consumer does not wait() if the condition already is true when it acquires the lock.

    If you follow the pattern, you will never lose a notification. If the producer happens to acquire the lock first, then the consumer will be guaranteed not to call lock.wait() once it gets hold of the lock. If the consumer happens to acquire the lock first, then it's guaranteed to be safely in the wait() call, and ready to receive the notification before the producer can send it.