生产者-消费者代码的Java多线程处理没有提供正确的输出?
我正在使用多线程处理处理经典的生产者-消费者问题。我在代码中使用了生产者-消费者代码的Java多线程处理没有提供正确的输出?,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我正在使用多线程处理处理经典的生产者-消费者问题。我在代码中使用了wait()和notifyAll()。我的问题是,当notifyAll通知另一个等待恢复的线程时,它不会立即恢复。为什么呢?代码如下 public class ConsumerProducer { private int count; public synchronized void consume() { while (count == 0) { // keep waiting if nothing is pro
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();
}
}
打印上面的第一行后,将调用notifyAll,等待的线程应继续,在消耗0后打印thread-2
。我看到的问题是在Thread-1(生产后的Thread-1)
完成后,Thread-2恢复。但这两个都应该同时发生?
请帮帮我。
谢谢
编辑:
在main方法中使用join(),未更改输出:
producer.start();
producer.join();
consumer.start();
但这两个都应该同时发生
这里的问题是生产(和消费)花费的时间很少。你看到的是所谓的a(非关键),生产者能够在消费者开始之前生产所有10种产品。我所说的竞态条件是指两个线程相互竞态以生产和消费,而不是本例中的bug
如果您将测试增加到(比方说)100000项,您将看到生成和使用消息的混合,尽管即使如此,您可能会看到生成的和消费的消息块的长度为10或更长
另一种尝试是先启动消费者,然后放一个线程。sleep(10)代码>在您启动它之后,以便它等待生产者。然后,消费者将有时间调用wait()
,并且在调用第一个notifyAll()
时,消费者将从wait
移动到BLOCKED
。但即使如此,竞争条件也可能显示在消费之前所有产生的消息。这就是多线程应用程序的异步特性
p、 正确处理中断异常总是一个好模式。你应该这样做:
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;
}
:
在当前线程放弃对该对象的锁定之前,唤醒的线程将无法继续。唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极竞争以在此对象上同步;例如,唤醒的线程在成为下一个锁定此对象的线程时没有可靠的特权或缺点
您看到的只是这两个线程的调度方式。正如大多数人告诉您的,程序输出并没有错误。理解原因是你的挑战
Calling.notifyAll()不保证通知线程(生产者)将立即停止执行,也不保证等待通知的线程(使用者)将立即开始执行。这两个线程可以“并发”执行,也可以不执行。线程由操作系统的线程调度程序控制。如果要增加for循环中的迭代次数,您可能会看到消息开始交错,因为操作系统在CPU上下交换两个线程,但它们不一定交错——没有人说它们必须交错——它们可能只是交错而已。此外,交错的粒度(如果发生的话)也不能保证
发送通知只能保证,如果另一个线程在“等待”中被阻塞,该线程最终将被唤醒。此外,消费者不一定会总共醒来10次。通知仅对在“等待”调用中被阻止的线程有意义。您可能会发送10个通知,但只进入和退出对的呼叫。请等待一次(或从不)。如果在没有线程的情况下发送通知。请稍候,该通知将“丢失”。这就是为什么一些其他信息通常与等待/通知结合使用,如计数、布尔值或队列。使用java.util.concurrent类,它们可以为您执行所有同步。它肯定提供了正确的输出。它没有给出您期望的输出。线程被“给予”执行时间。您看到的是线程调度在一段时间后从一个线程切换到另一个线程。在wait
状态下,线程将被过度查找以进行调度。即使调用notify
,将“等待”线程置于“我现在可以继续”状态,线程调度程序也不会立即切换到该状态。你可以使用Thread.sleep
或Thread.yield
之类的方法来鼓励调度人移动到下一个线程…@Gray我不是有意暗示他/她不是。我只是想强调通知的暂时性。我不会说正在发生的是“竞争条件”。对我来说,竞争条件是共享资源没有得到正确保护以避免并发访问的错误。我们这里的情况只是一个不直观的(对OP)操作顺序,但是共享资源(count
字段)得到了适当的保护,防止并发访问,并且程序执行正确。是的,我在@AdrianPronk之前已经讨论过这个问题。对我来说,“竞争条件”是任何类型的线程竞争——它不一定是一个bug。在这里,生产者向前运行,在消费者开始之前生产所有10个项目。这就是比赛。在线程编程中,有很多次在没有损坏的情况下进行竞争,但是由于竞争,输出仍然是意外的。“由于对事件相对时间的意外临界依赖而导致的异常行为”。来源:维基百科区分了“非关键竞争条件”(不会导致bug的竞争)和“关键竞争条件”(可能导致bug的竞争)。OP的例子是,我认为
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;
}