我的 Java 学习笔记 · 第 11 篇:Condition.await 为什么必须放在 while 里

Condition.await 为什么必须放在 while 里

上一回看了 Java 线程的状态。这次继续看并发里一个容易写错的地方:线程拿到锁后发现条件还不满足,应该怎么等?

以银行转账为例:转出账户余额不足时,当前线程不能继续转账。但如果它拿着锁一直循环检查,其他线程也拿不到这把锁,余额就没有机会改变。Condition 让线程可以在等待条件时暂时放开关联的锁。

java 复制代码
private final Lock bankLock = new ReentrantLock();
private final Condition sufficientFunds = bankLock.newCondition();

void transfer(int from, int to, int amount) throws InterruptedException {
    bankLock.lock();
    try {
        while (accounts[from] < amount) {
            sufficientFunds.await();
        }

        accounts[from] -= amount;
        accounts[to] += amount;
        sufficientFunds.signalAll();
    } finally {
        bankLock.unlock();
    }
}

这里的 accounts 是银行账户余额数组。检查余额、修改余额和发出通知都由同一把锁保护。

await 做了什么

调用 await() 时,当前线程会进入这个 Condition 的等待队列,并原子地释放关联的锁。这样其他线程才有机会拿到锁、修改余额。收到通知后,等待线程还要重新竞争并拿回这把锁,await() 才会返回。

所以 signalAll() 不会让等待线程立刻执行。它只是唤醒等待者;发出通知的线程仍持有锁,直到 finally 中解锁后,等待者才能继续竞争。

为什么要用 while,不能只检查一次

通知表达的是"条件可能变了",不保证线程醒来时条件仍成立。比如多个转账线程都在等同一个账户,余额变化后它们被一起唤醒;先拿回锁的线程可能已经取走了余额,后面的线程必须再检查一次。Condition 也允许虚假唤醒。

因此应该反复检查条件:

java 复制代码
while (条件不满足) {
    condition.await();
}

若写成 if,线程醒来后只检查一次;条件仍不满足也会继续执行临界区里的操作。

通知也要配合状态变化

通常在共享状态发生变化、等待者可能因此继续时发出通知。教材的转账例子在余额更新后调用 signalAll(),让所有等待线程重新检查各自的条件。signal() 只唤醒一个等待线程;如果它醒来后仍不满足条件并再次等待,而其他等待者本来可以继续,系统就可能卡住。

调用 await()、signal() 或 signalAll() 时,必须持有这个 Condition 关联的锁。记住这几个步骤:拿锁、循环检查条件、不满足就 await;改变状态后发通知,最后释放锁。

参考:Java SE 21 Condition API 文档。

相关推荐
学长毕设2 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
zzu123zsw3 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
源码集结号4 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
论文复现现场4 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
啃瓜子的松鼠5 小时前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David5 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
外收内放5 小时前
Python基础语法练习题(73)
java·前端·python
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 环信后台发送消息测试
java·交友
用户3721574261356 小时前
Java 操作 Word 脚注和尾注:添加、读取与删除
java
小嘉丶学长6 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节