问题描述
下面是消费者生产者问题代码,但是代码没有按预期工作.在这里,消费者和生产者应该只是生产和消费一个对象.
Below is the consumer producer problem code, but the code is not working as expected. Here the consumer and producer are supposed to be just producing and consuming one object.
public class ProducerConsumer {
private static LinkedList<Integer> linkedList = new LinkedList<>();
public static void main(String a[]) throws InterruptedException {
Thread producer = new Thread(new Runnable() {
@Override
public void run() {
synchronized(this) {
while (linkedList.size() == 1) {
try {
wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced");
linkedList.add(1);
notify();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread consume = new Thread(new Runnable() {
@Override
public void run() {
// produce
synchronized(this) {
while (linkedList.isEmpty()) {
try {
wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Consumed");
linkedList.removeFirst();
notify();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
});
producer.start();
consume.start();
producer.join();
consume.join();
}
}
我们得到的输出为:Produced
We get the output as : Produced
然后程序挂了.
请帮助提供可能的解决方案/解释
Please help with possible solutions/ explanations
推荐答案
使用共享锁.在发布的代码中,每个 Runnable 都将自己用作锁,因此不会发生实际的锁定.
Use a shared lock. In the posted code each Runnable is using itself as a lock so no actual locking takes place.
当一个线程等待时,另一个线程需要在相同锁上调用notify来唤醒等待的线程.我们从您的日志中知道生产者线程在做它的事情,但是由于通知作用于与消费者使用的锁不同的锁,因此消费者线程永远不会唤醒.
When a thread waits, another thread needs to call notify on the same lock in order to wake up the waiting thread. We know from your logging that the Producer thread does its thing, but since the notify acts on a lock that is not the same as the one the Consumer is using, the consumer thread never wakes up.
更改代码以使用共享锁有效:
Changing the code to use a shared lock works:
import java.util.*;
public class ProducerConsumer { private static LinkedList linkedList = new LinkedList();
public static void main(String a[]) throws InterruptedException {
final Object lock = new Object();
Thread producer = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
while (linkedList.size() ==1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced");
linkedList.add(1);
lock.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread consume = new Thread(new Runnable() {
@Override
public void run() {
// produce
synchronized (lock) {
while (linkedList.isEmpty()) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Consumed");
linkedList.removeFirst();
lock.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
producer.start();
consume.start();
producer.join();
consume.join();
}
}
输出为:
c:\example>java ProducerConsumer
Produced
Consumed
我认为这正是您所期望的.
which I think is what you're expecting.
顺便说一句,请参阅我写的另一个答案,了解简单的队列实现;保护共享数据结构比将代码放在访问数据结构的线程中更好,尤其是看看代码编写起来容易得多.
Btw see this other answer I wrote for a dirt-simple implementation of a queue; you are better off protecting the shared data structure than putting the code in the threads accessing the data structure, especially look at how much easier the code is to write.
这篇关于java中的线程生产者消费者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!