在维基上,我发现生产者 - 消费者程序的以下伪代码,其竞争条件可能导致死锁:
int itemCount = 0;
procedure producer()
{
while (true)
{
item = produceItem();
if (itemCount == BUFFER_SIZE)
{
sleep();
}
putItemIntoBuffer(item);
itemCount = itemCount + 1;
if (itemCount == 1)
{
wakeup(consumer);
}
}
}
procedure consumer()
{
while (true)
{
if (itemCount == 0)
{
sleep();
}
item = removeItemFromBuffer();
itemCount = itemCount - 1;
if (itemCount == BUFFER_SIZE - 1)
{
wakeup(producer);
}
consumeItem(item);
}
}
通过此实现,应该发生以下情况:
消费者刚刚阅读了变量itemCount,注意到它为零并且即将移动到if块内。
在呼叫睡眠之前,消费者被中断并且生产者被恢复。
制作人创建一个项目,将其放入缓冲区,并增加itemCount。
因为缓冲区在最后一次添加之前是空的,所以生产者试图唤醒消费者。
不幸的是,消费者还没有睡觉,唤醒电话就丢失了。当消费者恢复时,它会进入睡眠状态,永远不会再被唤醒。这是因为当itemCount等于1时,生产者只会唤醒消费者。
生产者将循环,直到缓冲区已满,之后它也将进入休眠状态。
我希望能够在Java中复制它,但到目前为止,我无法多次运行我的程序。这是我的代码:
private LinkedList<Integer> sharedList = new LinkedList<Integer>();
private int sharedValue = 0;
private int MAX_LIMIT = 10;
public void produce() throws InterruptedException {
Random random = new Random();
while (true) {
synchronized (this) {
if (sharedValue == MAX_LIMIT) { //'produce' thread waits if list is full
wait();
}
sharedValue = sharedValue + 1;
sharedList.add(sharedValue); System.out.println("added value: " + sharedValue);
if (sharedValue == 1) {
notify(); //notifies 'consume' thread if list is not empty
}
}
}
}
public void consume() throws InterruptedException {
Random random = new Random();
while (true) {
synchronized (this) {
if (sharedValue == 0) { //'consume' waits if list is empty
wait();
}
sharedValue = sharedValue - 1;
sharedList.remove(); System.out.println("removed value: " + sharedValue);
if (sharedValue == MAX_LIMIT-1) {
notify(); //notifies 'produce' if list is not full
}
}
Thread.sleep(random.nextInt(1000));
}
}
答案 0 :(得分:1)
原因是您同步整个迭代步骤。 <{1}}下的两个代码块将按顺序运行。
你可以用以下方式复制它:
synchronized (this) {...}