PowerFlower
PowerFlower

Reputation: 1619

Java: wait, notify

the code at the bottom (1) was just for exercising but makes me curious why always the same Thread and only this Thread is able to receive the resource made by the producer. When I update the producer part with a Thread.sleep in my code like (2) all Threads get the resource randomly (I think). But why? Does the Sheduler works with LIFO? Or whats the "problem" here?

1

public class ProducerConsumer {
private static int resource = 0;
private static AtomicInteger id = new AtomicInteger();

public static void main(String... args) throws InterruptedException {
    final Object monitor = new Object();
    Runnable producer = () -> {
        try {
            while (!Thread.interrupted()) {
                // produce number
                println("producing ...");
                int number = (int) (Math.random() * 1000) + 1;
                Thread.sleep(number);
                println("produced " + number);

                // send number
                synchronized (monitor) {
                    resource = number;
                    println("notified");
                    monitor.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            println("interrupted");
        }
    };
    Runnable consumer = () -> {
        final int innerId = id.getAndIncrement();
        try {
            while (!Thread.interrupted()) {
                // receive number
                int number;
                synchronized (monitor) {
                    while (resource == 0) {
                        println(innerId + " waiting ...");
                        monitor.wait();
                        println(innerId + " woke up ...");
                    }
                    number = resource;
                    resource = 0;
                }

                // consume number
                println("consumed " + number);
            }
        } catch (Exception e) {
            println("interrupted");
        }
    };

    new Thread(producer).start();
    new Thread(consumer).start();
    new Thread(consumer).start();
    new Thread(consumer).start();
    new Thread(consumer).start();
    Thread.sleep(10_000);
    Thread.currentThread().getThreadGroup().interrupt();

}

}

2

Runnable producer = () -> {
        try {
            while (!Thread.interrupted()) {
                // produce number
                println("producing ...");
                final int number = (int) (Math.random() * 1000) + 1;
                Thread.sleep(number);
                println("produced " + number);
                synchronized (monitor) {
                    setResource(number);
                    println("notified");
                    Thread.sleep(100);
                    monitor.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            println("interrupted");
        }
    };

Upvotes: 1

Views: 162

Answers (1)

Lasse Meyer
Lasse Meyer

Reputation: 1479

It is pseudo-random.

From the notifyAll doc:

The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.

The implementation seems to fairly reliable (not random) in your case, but like the documentation says, it is not 100% reliable.

Upvotes: 1

Related Questions