关于生产者和消费者方法中包裹 signalAll() 的 if 语句的疑问

来源:4-8 如果被问偏向锁、轻量级锁、重量级锁

HotChoc

2021-05-27

问题

  1. 生产者和消费者方法中包裹 signalAll() 的 if 语句的疑问
        // Producer
        public void readDb() throws InterruptedException {
    
            var data = readData(); // 1s
            lock.lock();
            if (queue.size() == MAX) {
                notFull.await();
                return;
            }
    
    
            queue.add(data);
    
            if(queue.size() == 1) {
                notEmpty.signalAll();
            }
            lock.unlock();
    
        }
    
        // Comsumer
        public void calculate() throws InterruptedException {
            lock.lock();
            if(queue.size() == 0) {
                notEmpty.await();
                return;
            }
    
            var data = queue.remove();
    
            System.out.println("queue-size:" + queue.size());
    
            if(queue.size() == MAX-1) {
                notFull.signalAll();
            }
    
            data *= 100;
            lock.unlock();
        }
    
    为什么要在 queue.size() == 1 和 queue.size() == MAX - 1 的时候再去 signalAll() 呢?add() 和 remove() 完之后应该不需要判断 queue.size() 就可以 signalAll() 了吧?
  2. await() 后为什么要接着 return?应该可以直接执行下面的步骤吧?

我的代码

这是我的代码,运行也没有发生死锁,请老师指教下上述两个问题,谢谢!

	void readDb() {
        lock.lock();
        try {
            while (queue.size() == CAPACITY) {
                // await() 会释放当前 Condition 绑定的锁
                full.await();
            }

            int data = readData();
            queue.offer(data);
            System.out.println(Thread.currentThread().getName() + " read " + data + ", size: " + queue.size());

            empty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void calculate() {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                // await() 会释放当前 Condition 绑定的锁
                empty.await();
            }

            Integer data = queue.poll();
            System.out.println(Thread.currentThread().getName() + " calculate " + data + ", size: " + queue.size());

            full.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
写回答

1回答

求老仙

2021-05-30

你提的两个问题之所以会有判断主要是性能考虑,await/wait这些最终最终都是很复杂的操作。比起一行判断来说,更消耗资源。 

1
0

笑傲Java面试 剖析大厂高频面试真题 秒变offer收割机

深度剖析大厂面试高频真题,让你秒变offer收割机

1783 学习 · 314 问题

查看课程