【问题标题】:Blocked using wait() and notify() in Java在 Java 中使用 wait() 和 notify() 阻塞
【发布时间】:2016-07-24 12:39:34
【问题描述】:

我正在使用 Java 中的 wait()notify() 编写生产者和消费者代码。 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();
      }
    }
  }
}

问题是在执行过程中,程序在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....

我无法理解这里有什么问题。我以某种方式发现将while循环中的代码包装在produce()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();
                }
            }

这里有什么问题?是线程饥饿还是死锁?

编辑:调用类:

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


    }
}

【问题讨论】:

  • 如何调用生产和消费方法?能否请您发布该代码?
  • @Divers 使用调用类编辑帖子。
  • 这不是死锁。死锁需要两个或更多锁。

标签: java multithreading synchronized producer-consumer


【解决方案1】:

当您执行list.size() 时,它不是线程安全的,也没有任何保证,您将永远看到另一个线程中的值发生了变化。如果 JIT 检测到您没有在该线程中更改它,它甚至可以内联该值。

通过将synchronized 块放在循环之外,您可以确保值的变化是可见的(因为它也在while(true) 循环内。

【讨论】:

  • 我还要补充一句:“比起notify,我更喜欢使用notifyAll
  • @MarkRotteveel - 糟糕的建议。 NotifyAll 效率低下。如果您需要依赖它,那么您的同步中的某些事情就不是最理想的了。
  • @StephenC 也许,但如果你有 - 例如 - 多个生产者和消费者,那么消费者可能会唤醒消费者,生产者可能会唤醒生产者,如果你不走运,可能需要一段时间才能发生任何事情.
  • 你不应该让生产者和消费者在同一件事上等待。事实上,使用不同的同步结构可能会更好地实现。例如一个队列/双端队列
  • @PeterLawrey 我同意。但在大部分Java面试题中,这些低级同步题却泛滥成灾。
【解决方案2】:

使用synchronized 外部循环创建read barrier。因此生产者/消费者将在您正在检查list.size() 的循环内看到最新的list。这就是为什么在您将 while 循环移动到 synchronized 块内后它起作用的原因。

在您的情况下,我还建议您在生产者/消费者中使用单个同步块。

例如,在您的实现中,如果list.size() == 0 成为消费者的false,它将释放lock 对象上的锁定,然后在下一条语句中尝试再次重新获取锁定以使用数据,这是不必要且低效的.应该是这样的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2011-02-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多