Producer/Consumer 多线程死锁 Java
Producer/Consumer deadlock multithreading Java
我正在尝试使用多线程解决 Java 中的 Producer/Consumer 问题,但我一直陷入僵局,我不明白为什么。
BoundedBuffer.java
public class BoundedBuffer {
private final int[] buffer;
private final int N;
private int in = 0;
private int out = 0;
private int itemCount = 0;
public BoundedBuffer(int size) {
N = size + 1;
buffer = new int[N];
}
public void insert(Producer producer, int item) {
synchronized (producer) {
while ( (in + 1) % N == out) {
try {
producer.wait();
} catch (InterruptedException e) {}
}
buffer[in] = item;
in = (in + 1) % N;
itemCount++;
}
public int remove(Consumer consumer) {
synchronized (consumer) {
while (in == out) {
try {
consumer.wait();
} catch (InterruptedException e) {}
}
int item = buffer[out];
buffer[out] = null;
out = (out + 1) % N;
itemCount--;
return item;
}
}
}
Producer.java
public class Producer extends Thread {
private int total = 0;
private BoundedBuffer buffer;
private int uniqueItem = 0;
public Producer(int total, BoundedBuffer b) {
this.total = total;
this.buffer = b;
}
public void run() {
for (int i = 0; i < quota; i++) {
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {}
buffer.insert(this, uniqueItem++);
this.notifyAll();
}
}
}
Consumer.java
public class Consumer extends Thread {
private int total = 0;
private BoundedBuffer buffer;
public Consumer(int total, BoundedBuffer b) {
this.total = total;
this.buffer = b;
}
public void run() {
for (int i = 0; i < total; i++) {
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {}
buffer.remove(this);
this.notifyAll();
}
}
}
这段代码会 运行 一段时间,当我设置调试 ("This producer is trying to insert this item...") 时,我看到一个很好的模式出现,但我时不时会收到这个错误:
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Consumer.run(Consumer.java:19)
然后我在那之后的某个时候发生了死锁。
我认为我的问题是由于我正在同步的密钥 producer
和 consumer
实例引起的。我不确定还有什么我可以同步方法,这是最让我难过的。我相信我可以为每个 consumer/producer 共享一个密钥,但我不确定它是如何工作的。
您应该在 BoundedBuffer
本身上进行同步,并在同步块内使用 wait
来释放锁并等待另一个线程通知正在休眠的线程。
本教程中有一个完整的示例:
https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
另外,请注意,您现在可以使用 BlockingQueue
以更简单的方式实现消费者-生产者模式。
这里有 BlockingQueue
的文档,显示了更简单的消费者-生产者实现:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
我正在尝试使用多线程解决 Java 中的 Producer/Consumer 问题,但我一直陷入僵局,我不明白为什么。
BoundedBuffer.java
public class BoundedBuffer {
private final int[] buffer;
private final int N;
private int in = 0;
private int out = 0;
private int itemCount = 0;
public BoundedBuffer(int size) {
N = size + 1;
buffer = new int[N];
}
public void insert(Producer producer, int item) {
synchronized (producer) {
while ( (in + 1) % N == out) {
try {
producer.wait();
} catch (InterruptedException e) {}
}
buffer[in] = item;
in = (in + 1) % N;
itemCount++;
}
public int remove(Consumer consumer) {
synchronized (consumer) {
while (in == out) {
try {
consumer.wait();
} catch (InterruptedException e) {}
}
int item = buffer[out];
buffer[out] = null;
out = (out + 1) % N;
itemCount--;
return item;
}
}
}
Producer.java
public class Producer extends Thread {
private int total = 0;
private BoundedBuffer buffer;
private int uniqueItem = 0;
public Producer(int total, BoundedBuffer b) {
this.total = total;
this.buffer = b;
}
public void run() {
for (int i = 0; i < quota; i++) {
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {}
buffer.insert(this, uniqueItem++);
this.notifyAll();
}
}
}
Consumer.java
public class Consumer extends Thread {
private int total = 0;
private BoundedBuffer buffer;
public Consumer(int total, BoundedBuffer b) {
this.total = total;
this.buffer = b;
}
public void run() {
for (int i = 0; i < total; i++) {
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {}
buffer.remove(this);
this.notifyAll();
}
}
}
这段代码会 运行 一段时间,当我设置调试 ("This producer is trying to insert this item...") 时,我看到一个很好的模式出现,但我时不时会收到这个错误:
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Consumer.run(Consumer.java:19)
然后我在那之后的某个时候发生了死锁。
我认为我的问题是由于我正在同步的密钥 producer
和 consumer
实例引起的。我不确定还有什么我可以同步方法,这是最让我难过的。我相信我可以为每个 consumer/producer 共享一个密钥,但我不确定它是如何工作的。
您应该在 BoundedBuffer
本身上进行同步,并在同步块内使用 wait
来释放锁并等待另一个线程通知正在休眠的线程。
本教程中有一个完整的示例: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
另外,请注意,您现在可以使用 BlockingQueue
以更简单的方式实现消费者-生产者模式。
这里有 BlockingQueue
的文档,显示了更简单的消费者-生产者实现:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html