W
W
WTFAYD2017-09-19 18:45:10
Java
WTFAYD, 2017-09-19 18:45:10

Why is another monitor (not this) specified in the synchronized block?

Below is a code snippet from the Java Philosophy tutorial. It briefly describes the producer-consumer concept in multithreading.
The general gist is that in the restaurant ( Restaurant ) there is one cook ( Chef ) and one waiter ( WaitPerson ). The waiter waits ( wait ) while the cook prepares the dish ( Meal ). When the chef has prepared a dish, he notifies ( notify ) the waiter, who receives the dish, takes it to the client and starts waiting again.
Please tell me why as an object for the second synchronized block , in which the notifyAll () method is located (for example, this is rest.chef in the WaitPerson class), is not this used , as in the first case? There is an idea that this is due to the fact that it is the chef who needs to be awakened, and not the waiter, I want to dispel doubts.

class WaitPerson implements Runnable {
    private Restaurant rest;

    public WaitPerson(Restaurant r) {
        rest = r;
    }

    @Override
    public void run() {
        try {
            while(!Thread.interrupted()) {
                synchronized (this) {
                    while (rest.meal == null)
                        wait(); // ... for the chef to produce a meal
                }
                System.out.println("Waitperson got " + rest.meal);
                synchronized (rest.chef) {
                    rest.meal = null;
                    rest.chef.notifyAll(); // ready for another
                }
            }
        } catch(InterruptedException e) {
            System.out.println("WaitPerson interrupted");
        }

    }
}

class Chef implements Runnable {
    private Restaurant rest;
    private int count = 0;

    public Chef(Restaurant r) {
        rest = r;
    }

    @Override
    public void run() {
        try {
            while(!Thread.interrupted()) {
                synchronized (this) {
                    while(rest.meal != null)
                        wait(); // ... for the meal to be taken
                }
                if(++count == 10) {
                    System.out.println("Out of food");
                    rest.exec.shutdownNow();
                }
                System.out.print("Order up! ");
                synchronized (rest.waitPerson) {
                    rest.meal = new Meal(count);
                    rest.waitPerson.notifyAll();
                }
                TimeUnit.MILLISECONDS.sleep(100);
            }

        } catch(InterruptedException e) {
            System.out.println("Chef interrupted");
        }
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
P
pi314, 2017-09-19
@WTFAYD

So it is, moreover, for both )) In fact, both compete for one resource rest.meal, but not "globally", but separately for two different operations with it - in the first block for reading, in the second for writing. With the synchronize(this) block, each of them hangs the monitor on himself, his beloved, performs reading and begins to wait for a kick from the other. With the second block, he hangs the monitor on another, performs a recording and kicks the other. This could be written a little more elegantly and more readably using higher-level abstractions from java.util.concurrent (where almost the same thing would happen under the hood), but the essence of the example, as far as I understand, is precisely to show how in such situations purposefully synchronize two threads with each other directly, so that each only reads once and writes once.
Also note that none of them are synchronized with the resource itself, which allows, for example, in the future, not to block other threads that are somehow related to this resource without a clear need.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question