Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blocked using wait() and notify() in Java

I am writing producer and consumer code using wait() and notify() in Java. Thread-0 is created and is invoked on produce() and Thread-1 is created and is invoked on consume().

public class Processor {

  private volatile List<Integer> list = new ArrayList<>();
  private final int MAX_CAPACITY = 5;
  Object lock = new Object();

  public void produce() throws InterruptedException {

    while (true) {

      while (list.size() == MAX_CAPACITY) {
        System.out.println("List is full! Producer is Waiting....");
        synchronized (lock) {
          lock.wait();
        }
      }

      synchronized (lock) {
        int random = new Random().nextInt(100);
        list.add(random);
        System.out.println("Added to list:" + random);
        lock.notify();
      }
    }
  }

  public void consume() throws InterruptedException {

    while (true) {

      while (list.size() == 0) {
        System.out.println("List is empty!! Consumer is Waiting...");
        synchronized (lock) {
          lock.wait();
        }
      }

      synchronized (lock) {
        int i = list.remove(0);
        System.out.println("Removed from list:" + i);
        lock.notify();
      }
    }
  }
}

The problem is that during execution, program stops after produce():

List is empty!! Consumer is Waiting...
Added to list:22
Added to list:45
Added to list:72
Added to list:91
Added to list:51
List is full! Producer is Waiting....

I am not able to understand what's the problem here. I somehow figured out that wrapping the code from while loop in synchronized block in produce() and consume() solves the problem.

produce()

synchronized (lock) {
                while (list.size() == MAX_CAPACITY) {
                    System.out.println("List is full! Producer is Waiting....");

                    lock.wait();
                }

consume

synchronized (lock) {
                while (list.size() == 0) {
                    System.out.println("List is empty!! Consumer is Waiting...");

                    lock.wait();
                }
            }

What is the issue here? Is it a case of Thread starvation or deadlock?

Edit: Calling class:

public class App {
    public static void main(String[] args) {
        final Processor processor = new Processor();

        Runnable r1 = new Runnable() {

            @Override
            public void run() {
                try {
                    processor.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };

        Runnable r2 = new Runnable() {

            @Override
            public void run() {
                try {
                    processor.consume();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
        };

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();


    }
}
like image 799
Anurag Avatar asked May 25 '26 09:05

Anurag


1 Answers

When you perform list.size() it is not thread safe and there is no guarentee you will ever see the value changed in another thread. The JIT could even inline the value if it detects you are not changing it in that thread.

By placing the synchronized block outside the loop you ensure a change in the value is visible (as it is also inside the while(true) loop.

like image 74
Peter Lawrey Avatar answered May 27 '26 22:05

Peter Lawrey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!