多线程多线程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();
# 1 楼答案
正如这里的大多数人告诉你的,程序输出并没有错误。理解原因是你的挑战
打电话。notifyAll()不保证通知线程(生产者)立即停止执行,也不保证等待通知的线程(消费者)立即开始执行。这两个线程可以同时执行,也可以不执行。线程由操作系统的线程调度程序控制。如果要增加for循环中的迭代次数,当操作系统交换CPU上下两个线程时,您可能会看到消息开始交错,但它们不一定会交错,因为它们只是可能。此外,交错的粒度(如果发生的话)也无法保证
发送通知只会保证如果另一个线程在“wait”中被阻塞,该线程最终将唤醒。此外,消费者不一定会总共醒来10次。通知仅对在“等待”调用中被阻止的线程有意义。您可能会发送10个通知,但只进入和退出对的通话。等一次(或永远不要等)。如果在没有线程时发送通知。等等,通知“丢失了”。这就是为什么其他一些信息通常与等待/通知结合使用,比如计数、布尔值或队列
# 2 楼答案
From the notify (and notifyAll) docs
您看到的只是这两个线程的调度方式
# 3 楼答案
这里的问题是,生产(和消费)只需要很少的时间。你看到的是所谓的a(非关键的)race condition,生产商甚至可以在消费者开始之前生产所有10种产品。我所说的竞速条件是指两个线程相互竞速生产和消费,而不是本例中的bug
如果您将测试增加到(比方说)100000项,您将看到生成和使用消息的混合,尽管即使这样,您可能会看到长度为10或更长的
producing
和consuming
消息块另一种尝试是先启动消费者,然后在启动后放置一个
Thread.sleep(10);
,这样它就在等待生产者。然后,消费者将有时间调用wait()
,并且在调用第一个notifyAll()
时,消费者将从WAIT
移动到BLOCKED
。但即便如此,竞争条件也可能会在consuming
之前显示所有producing
消息。这就是多线程应用程序的异步本质另外,正确处理
InterruptedException
总是一个好模式。你应该这样做: