BlockingQueue дизайн с несколькими мониторами - PullRequest
3 голосов
/ 29 октября 2011

Я пишу BlockingQueue и мне интересно, как другие реализации решают эту проблему:

Если у меня есть только один монитор (объект очереди), и пусть производители и потребители wait, я должен убедиться, что вызывается notifyAll вместо notify, в противном случае производитель может только сигнализировать другому ожидающему производителю продолжить, даже если очередь заполнена. Заставить потребителя ждать, несмотря на то, что товар доступен. С другой стороны, вызов notifyAll не представляется масштабируемым решением для многих потоков и процессоров.

Используют ли BlockingQueue два монитора? Один ожидал производителей, а второй - потребителей? Тогда мне придется синхронизировать очередь и соответствующий монитор в инкапсулированном виде. Это путь?

Ответы [ 2 ]

5 голосов
/ 29 октября 2011

Я не уверен, как это сделать в BlockingQueue, но одно из возможных решений - использовать ReentrantLock вместо synchronized.

Он имеет ту же семантику, что и syncrhonized, но обеспечивает некоторые улучшения.В частности, он может иметь несколько условий, в которых другие потоки могут wait включить:

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();
        }
    }
    ...
}
1 голос
/ 29 октября 2011

В общем, использование notifyAll() - лучший подход по сравнению с notify(). Как вы упомянули, вы можете использовать два объекта монитора, один для чтения и один для доступа для записи.
Использование notify() вместо этого может быть подвержено ошибкам, и снижение производительности при использовании notifyAll() в большинстве случаев пренебрежимо и обычно не требует различного кодирования, поскольку каждый ожидающий поток должен быть подготовлен к ложным пробуждениям в любом случае.

...