有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程多线程Java中producerconsumer代码的多线程没有提供正确的输出?

我正在使用多线程处理处理经典的生产者-消费者问题。我在代码中使用了wait()notifyAll()。我的问题是,当notifyAll通知另一个等待恢复的线程时,它不会立即恢复。为什么呢?代码如下

public class ConsumerProducer {

 private  int count;

 public synchronized void consume() {
  while (count == 0) {  // keep waiting if nothing is produced to consume
   try {
    wait(); // give up lock and wait
   } catch (InterruptedException e) {
    // keep trying
   }
  }

  count--;              // consume
  System.out.println(Thread.currentThread().getName() + " after consuming " + count);
 }

 public synchronized void produce() {
  count++;             //produce
  System.out.println(Thread.currentThread().getName() + " after producing " + count);
  notifyAll();         // notify waiting threads to resume
 }

}

客户端代码:

public class ConsumerProducerTest implements Runnable {

 boolean isConsumer;
 ConsumerProducer cp;

 public ConsumerProducerTest(boolean isConsumer, ConsumerProducer cp) {
  this.isConsumer = isConsumer;
  this.cp = cp;
 }

 public static void main(String[] args) {
  ConsumerProducer cp = new ConsumerProducer(); //shared by both threads to communicate

  Thread producer = new Thread(new ConsumerProducerTest(false, cp));
  Thread consumer = new Thread(new ConsumerProducerTest(true, cp));

  producer.start();
  consumer.start();
  //producer.start();


 }

 @Override
 public void run() {
  for (int i = 1; i <= 10; i++) {
   if (!isConsumer) {
    cp.produce();
   } else {
    cp.consume();
   }
  }

输出为:

Thread-1 after producing 1
Thread-1 after producing 2
Thread-1 after producing 3
Thread-1 after producing 4
Thread-1 after producing 5
Thread-1 after producing 6
Thread-1 after producing 7
Thread-1 after producing 8
Thread-1 after producing 9
Thread-1 after producing 10
Thread-2 after consuming 9
Thread-2 after consuming 8
Thread-2 after consuming 7
Thread-2 after consuming 6
Thread-2 after consuming 5
Thread-2 after consuming 4
Thread-2 after consuming 3
Thread-2 after consuming 2
Thread-2 after consuming 1
Thread-2 after consuming 0

打印完上面的第一行后,调用notifyAll,等待的线程应该继续打印Thread-2 after consuming 0。我看到的问题是Thread-1 (Thread-1 after producing)完成后,线程2恢复。但这两种情况应该同时发生吗? 请帮帮我。 谢谢 编辑: 在main方法中使用join(),未更改输出:

 producer.start();
  producer.join();
  consumer.start(); 

共 (3) 个答案

  1. # 1 楼答案

    正如这里的大多数人告诉你的,程序输出并没有错误。理解原因是你的挑战

    打电话。notifyAll()不保证通知线程(生产者)立即停止执行,也不保证等待通知的线程(消费者)立即开始执行。这两个线程可以同时执行,也可以不执行。线程由操作系统的线程调度程序控制。如果要增加for循环中的迭代次数,当操作系统交换CPU上下两个线程时,您可能会看到消息开始交错,但它们不一定会交错,因为它们只是可能。此外,交错的粒度(如果发生的话)也无法保证

    发送通知只会保证如果另一个线程在“wait”中被阻塞,该线程最终将唤醒。此外,消费者不一定会总共醒来10次。通知仅对在“等待”调用中被阻止的线程有意义。您可能会发送10个通知,但只进入和退出对的通话。等一次(或永远不要等)。如果在没有线程时发送通知。等等,通知“丢失了”。这就是为什么其他一些信息通常与等待/通知结合使用,比如计数、布尔值或队列

  2. # 2 楼答案

    From the notify (and notifyAll) docs

    The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. 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.

    您看到的只是这两个线程的调度方式

  3. # 3 楼答案

    But both are supposed to happen concurrently?

    这里的问题是,生产(和消费)只需要很少的时间。你看到的是所谓的a(非关键的)race condition,生产商甚至可以在消费者开始之前生产所有10种产品。我所说的竞速条件是指两个线程相互竞速生产和消费,而不是本例中的bug

    如果您将测试增加到(比方说)100000项,您将看到生成和使用消息的混合,尽管即使这样,您可能会看到长度为10或更长的producingconsuming消息块

    另一种尝试是先启动消费者,然后在启动后放置一个Thread.sleep(10);,这样它就在等待生产者。然后,消费者将有时间调用wait(),并且在调用第一个notifyAll()时,消费者将从WAIT移动到BLOCKED。但即便如此,竞争条件也可能会在consuming之前显示所有producing消息。这就是多线程应用程序的异步本质

    另外,正确处理InterruptedException总是一个好模式。你应该这样做:

    try {
        wait(); // give up lock and wait
    } catch (InterruptedException e) {
        // reset the thread interrupt flag
        Thread.currentThread().interrupt();
        // probably stopping the thread is best
        return;
    }