具有多个监视器的BlockingQueue设计

发布于 2024-12-12 21:41:40 字数 357 浏览 1 评论 0原文

我正在编写一个 BlockingQueue,想知道其他实现如何解决这个问题:

如果我只有一个监视器(队列对象)并让生产者和消费者等待,我将必须确保 notifyAll调用 而不是 notify ,否则生产者可能只会向另一个等待的生产者发出信号以继续,即使队列已满。即使有东西可用,也要让消费者等待。另一方面,对于许多线程和处理器来说,调用 notifyAll 似乎不是一个可扩展的解决方案。

BlockingQueue 使用两个监视器吗?一种是生产者等待,一种是消费者等待?然后我必须以封装的方式同步队列和相关监视器。这是要走的路吗?

I am writing a BlockingQueue and am wondering how other implementations solve this problem:

If I only have one monitor (the queue object) and let producers and consumers wait, I will have to ensure that notifyAll instead of notify is called, otherwise a producer might only signal another waiting producer to continue even if the queue is full. Making the consumer wait even though stuff is available. On the other hand calling notifyAll doesn't seem to be a scalable solution for many threads and processors.

Do BlockingQueues use two monitors? One were the producers wait and one were the consumers wait? Then I would have to synchronize the the queue and the relavant monitor in a encapsulated manner. Is that the way to go?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

巾帼英雄 2024-12-19 21:41:40

我不确定它是如何在 BlockingQueue 中完成的,但一种可能的解决方案是使用 ReentrantLock 而不是同步

它具有与 syncrhonized 相同的语义,但提供了一些改进。特别是,它可以具有其他线程可以等待的几个条件:

public class MyBlockingQueue<E> {
    private Lock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public void put(E e) {
        lock.lock();
        try {
            while (isFull()) notFull.await();
            boolean wasEmpty = isEmpty();
            ...
            if (wasEmpty) notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public E take() {
        lock.lock();
        try {
            while (isEmpty()) notEmpty.await();
            boolean wasFull = isFull();
            ...
            if (wasFull) notFull.signal();
            ...
        } finally {
            lock.unlock();
        }
    }
    ...
}

I'm not sure how it's done in BlockingQueue, but one possible solution is to use ReentrantLock instead of synchronized.

It has the same semantics as syncrhonized, but provides some improvements. In particular, it can have several conditions other threads can wait on:

public class MyBlockingQueue<E> {
    private Lock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public void put(E e) {
        lock.lock();
        try {
            while (isFull()) notFull.await();
            boolean wasEmpty = isEmpty();
            ...
            if (wasEmpty) notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public E take() {
        lock.lock();
        try {
            while (isEmpty()) notEmpty.await();
            boolean wasFull = isFull();
            ...
            if (wasFull) notFull.signal();
            ...
        } finally {
            lock.unlock();
        }
    }
    ...
}
儭儭莪哋寶赑 2024-12-19 21:41:40

一般来说,与 notify() 相比,使用 notifyAll() 是更好的方法。正如您提到的,您可以使用两个监视器对象,一个用于读取,一个用于写入访问。
使用 notify() 可能容易出错,并且使用 notifyAll() 的性能损失在大多数情况下可以忽略不计,并且通常不需要不同的编码,因为每个等待的线程都必须无论如何,要为虚假唤醒做好准备。

In general, using notifyAll() is the better approach compared to notify(). As you mentioned you could use two monitor objects, one for read and one for write access.
Using notify() instead can be error prone and the performance penalty for using notifyAll() is in most cases neglectable and usually does not require different coding since each thread waiting has to be prepared for spurious wakeups anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文