使用 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
如果对象的监视器(内部锁)用于多个条件,则调用 notify
方法而不是 notifyAll
可能无法唤醒正确的线程。 notify
仅唤醒一个等待对象的监视器的任意线程,而 notifyAll
唤醒所有此类线程。
建议¶
确保调用 notify
而不是 notifyAll
是一个正确且可取的优化。如果不是,请改为调用 notifyAll
。
示例¶
在以下示例中,produce
和 consume
方法都使用 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
时,所有线程都会被通知,如果存在任何可以继续执行的线程,我们可以确保至少其中一个线程会执行。
参考¶
J. Bloch. 有效 Java(第二版),第 277 页。Addison-Wesley,2008 年。
Java API 规范:Object.notify(),Object.notifyAll().
通用弱点枚举:CWE-662.