简体   繁体   English

在Java中使用wait()和notify()进行阻止

[英]Blocked using wait() and notify() in Java

I am writing producer and consumer code using wait() and notify() in Java. 我正在使用Java中的wait()notify()编写生产者和消费者代码。 Thread-0 is created and is invoked on produce() and Thread-1 is created and is invoked on consume() . 创建Thread-0并在produce()上调用,并创建Thread-1并在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() : 问题是在执行期间,程序在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. 我以某种方式弄清楚将while循环中的代码包装在produce()consume()中的synchronized块中解决了这个问题。

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();


    }
}

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. 当你执行list.size()它不是线程安全的,并且没有保证你将看到另一个线程中的值发生了变化。 The JIT could even inline the value if it detects you are not changing it in that thread. 如果JIT检测到您没有在该线程中更改它,则它甚至可以内联该值。

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. 通过将synchronized块放在循环外部,可确保值的变化可见(因为它也在while(true)循环内while(true)

Using synchronized outside loop creates read barrier . 使用synchronized外部循环创建读取障碍 Therefore producer/consumer will see latest list inside loop where you are checking list.size() . 因此,生产者/消费者将在您检查list.size()环路中看到最新的list That is why it works after you move while loop inside synchronized block. 这就是为什么你移动后,它的工作原理while内循环synchronized块。

In your case I would also suggest you to use single synchronized block in producer/consumer. 在您的情况下,我还建议您在生产者/消费者中使用单个同步块。

For example in your implementation if list.size() == 0 becomes false for consumer, it will release lock on lock object then in the next statement try to re-acquire lock again for consuming the data, which is unnecessary and inefficient. 例如,在您的实现中,如果list.size() == 0对于使用者变为false ,它将释放对lock对象的锁定,然后在下一个语句中尝试再次获取锁定以消耗数据,这是不必要且低效的。 It should be like: 应该是这样的:

public void consume() throws InterruptedException {

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

        lock.wait();
      }

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM