Почему в Java BlockingQueue нет условия if для уведомления? - PullRequest
1 голос
/ 26 июня 2019

Я реализовал свой пользовательский BlockingQueue<T> и сравнил его с java.util.concurrent ArrayBlockingQueue.

Вот моя реализация:

public class CustomBlockingQueue<T> implements BlockingQueue<T> {

    private final T[] table;

    private final int capacity;

    private int head = 0;

    private int tail = 0;

    private volatile int size;

    private final Lock lock = new ReentrantLock();

    private final Condition notEmpty = lock.newCondition();

    private final Condition notFull = lock.newCondition();

    @SuppressWarnings("unchecked")
    public CustomBlockingQueue(final int capacity) {
        this.capacity = capacity;
        this.table = (T[]) new Object[this.capacity];
        size = 0;
    }

    @Override
    public void add(final T item) throws InterruptedException {
        lock.lock();
        try {
            while (size >= table.length) {
                notFull.await();
            }
            if (tail == table.length) {
                tail = 0;
            }
            table[tail] = item;
            size++;
            tail++;
            if (size == 1) {
                notEmpty.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    public T poll() throws InterruptedException {
        lock.lock();
        try {
            while (size == 0) {
                notEmpty.await();
            }
            if (head == table.length) {
                head = 0;
            }
            final T result = table[head];
            table[head] = null;
            size--;
            head++;
            if (size == capacity - 1) {
                notFull.signalAll();
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public int size() {
        return size;
    }

}

Моя реализация основана на массиве.

Я не прошу вас просмотреть код, но помогите мне прояснить разницу между моим и Java.

В моем коде я notEmpty.signalAll() или notFull.signalAll() внутри if пункт, но java.util.concurrent каждый просто вызывает signal() в каждом случае?

В чем причина уведомления другого потока каждый раз, даже если в этом нет необходимости?

1 Ответ

0 голосов
/ 26 июня 2019

Если поток блокируется до тех пор, пока он не сможет читать или добавлять в очередь, лучшее место для него - это набор ожидания для применимого условия.Таким образом, он не борется активно за блокировку и не переключается в контекст.

Если в очередь добавляется только один элемент, мы хотим сообщить об этом только одному потребителю.Мы не хотим сигнализировать большему количеству потребителей, чем у нас есть элементы в очереди, потому что это заставляет систему работать и управлять временными интервалами для всех потоков, которые не могут прогрессировать независимо.

Вот почему ArrayBlockingQueue сигнализирует по одному за каждый раз, когда элемент ставится в очередь или удаляется из очереди, чтобы избежать ненужных пробуждений.В вашей реализации все в waitset просыпаются при переходе (от пустого к непустому или от полного к не полному), независимо от того, сколько из этих потоков сможет выполнить свою работу.

Это становится более значительным, так как большее количество потоков сталкивается с этим одновременно.Представьте себе систему с 100 потоками, ожидающими что-то из очереди, но каждые 10 секунд добавляется только один элемент.Было бы лучше не выбрасывать 100 потоков из waitset, чтобы 99 из них вернулись.

...