CodeQL 文档

使用 notify 而不是 notifyAll

ID: java/notify-instead-of-notify-all
Kind: problem
Security severity: 
Severity: warning
Precision: medium
Tags:
   - reliability
   - correctness
   - concurrency
   - external/cwe/cwe-662
Query suites:
   - java-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

如果对象的监视器(内部锁)用于多个条件,则调用 notify 方法而不是 notifyAll 可能无法唤醒正确的线程。 notify 仅唤醒一个等待对象的监视器的任意线程,而 notifyAll 唤醒所有此类线程。

建议

确保调用 notify 而不是 notifyAll 是一个正确且可取的优化。如果不是,请改为调用 notifyAll

示例

在以下示例中,produceconsume 方法都使用 notify 来告诉任何等待的线程已将对象添加到缓冲区或从缓冲区中删除。但是,这意味着仅通知一个线程。由于其条件为假,因此被唤醒的线程可能无法继续执行,立即返回到等待状态。因此,不会有任何进展。

class ProducerConsumer {
    private static final int MAX_SIZE=3;
    private List<Object> buf = new ArrayList<Object>();

    public synchronized void produce(Object o) {
        while (buf.size()==MAX_SIZE) {
            try {
                wait();
            }
            catch (InterruptedException e) {
               ...
            }
        }
        buf.add(o);
        notify(); // 'notify' is used
    }

    public synchronized Object consume() {

        while (buf.size()==0) {
            try {
                wait();
            }
            catch (InterruptedException e) {
                ...
            }
        }
        Object o = buf.remove(0);
        notify(); // 'notify' is used
        return o;
    }
}

当使用 notifyAll 而不是 notify 时,所有线程都会被通知,如果存在任何可以继续执行的线程,我们可以确保至少其中一个线程会执行。

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私