同步方法中的BlockedLinkedQueue死锁

时间:2009-09-30 04:33:37

标签: java deadlock

这可能是一个新手问题 - 我在使用BlockedLinkedQueue时遇到了死锁情况 - 这是我的代码剪辑:

public class mytest {
    private BlockedLinkedQueue myQueue;

    public synchronized void consumer() {
        ...
        myQueue.take()
        ...
    }

    public synchronized void producer() {
        ...
        myQueue.put()
        ...
    }
}

我注意到有时候我遇到了僵局。许多producer()线程正在方法监视器上等待,并且一个使用者在take()上被阻塞。这是预期的吗?我知道我不需要同步BLockedLinkedQUeue - 但我有很多其他对象,我需要同步这些方法..

2 个答案:

答案 0 :(得分:8)

是的,预计会出现这种僵局。使用空队列调用consumer()时会发生这种情况。在这种情况下,consumer()保持锁定“this”并等待myQueue中的对象。同一时间任何producer()都不能锁定“this”(由消费者持有),因此不能将任何对象放到myQueue上,这会阻止消费者获取对象。

要解决死锁问题,您可以只使部分方法同步或使用简单队列并实现自己的等待数据。 部分同步的示例:

public class mytest {
private BlockedLinkedQueue myQueue;

public void consumer() {
    synchronized(this) {
        ...
    }
    myQueue.take();
    synchronized (this) {
        ...
    }
}

public void producer() {
    synchronized(this) {
        ...
    }
    myQueue.put()
    synchronized(this) {
        ...
    }
}
}

在这种情况下,在myQueue操作期间释放锁定“this”。它将允许producer()进行处理并将对象放入队列。

第二个例子:

public class mytest {
private Queue myQueue;

public synchronized void consumer() {
    ...
    while (myQueue.isEmpty()) {
        this.wait();
    }
    myQueue.take()
    ...
}

public synchronized void producer() {
    ...
    myQueue.put()
    this.notify();
    ...
}
}

在此示例中,在调用this.wait()期间释放对“this”的锁定(有关详细信息,请参阅Object.wait()),它允许producer将对象放入队列。此外,制片人唤醒了一位等待数据的消费者。

请注意,在这两种情况下,只执行一半“消费者”方法时,将执行生产者方法。即消费者方法根本不是原子的,而只是它的一半。如果你需要消费者的原子性,那么你应该考虑更好地规范生产者/消费者方法,因为所描述的死锁是“同步”中的逻辑缺陷。在执行“atomic”consumer()方法时不能放置对象,同时consumer()要求对象在队列中。

答案 1 :(得分:1)

BlockedLinkedQueue?我认为你的意思是 LinkedBlockingQueue

LinkedBlockingQueue是线程安全的,你不应该将它隐藏在同步方法修饰符后面。删除这些将可能会结束您的死锁问题。自由使用同步通常不是一个好主意 - 将其保持在最低限度,只需在您需要的地方。

正如maxkar指出的那样, BlockingQueue.take() 等待队列中的某些内容。

  

检索并删除此头部   队列,必要时等待直到   元素变得可用。

如果您坚持要在班级consumer()方法上保持同步,请考虑使用 BlockingQueue.poll(long timeout, TimeUnit unit) 。这将允许您制作优雅地处理空队列的逻辑。