为什么在Java BlockingQueue中没有notify的if子句?

时间:2019-06-26 12:59:14

标签: java multithreading concurrency java.util.concurrent blockingqueue

我实现了自定义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 :(得分:0)

如果某个线程在可以读取队列或添加到队列之前一直处于阻塞状态,则该线程的最佳位置是在适用条件的等待集中。这样一来,它就不会主动争夺锁,也不会被上下文切换到其中。

如果只有一项添加到队列中,我们只希望发信号通知一位消费者。我们不想向更多的消费者发出信号,而不是让队列中有更多的项目,因为这使系统不得不管理更多工作,并给所有无法取得进展的线程分配时间片。

这就是为什么ArrayBlockingQueue每次将一个项目入队或出队时每次发出一个信号的原因,以避免不必要的唤醒。在您的实现中,等待集中的每个人(从空到非空,或从满到不满)都会被唤醒,无论这些线程中有多少个能够完成其工作。

随着越来越多的线程同时达到这个目标,这一点变得更加重要。想象一下一个有100个线程正在等待消耗队列中某些内容的系统,但是每10秒仅添加一项。最好不要从waitset中踢出100个线程,只是要让其中的99个线程返回。