You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Condition#await(long, TimeUnit)如何处理虚假唤醒并设置超时?

使用Condition#await(long, TimeUnit)处理虚假唤醒的惯用方式

处理带超时的Condition等待时,应对虚假唤醒的核心思路和无参版本一致:用循环持续检查目标条件,同时结合await(long, TimeUnit)的返回值判断最终退出原因。

核心逻辑说明

Condition.await(long, TimeUnit)会在三种场景下返回:

  • 其他线程调用signal/signalAll,当前线程被唤醒
  • 等待时间到达设定的超时阈值
  • 当前线程被中断

虚假唤醒属于第一种场景,但此时目标条件(比如示例中的flag)并未满足,因此必须在循环中重新检查条件——只要条件不满足,就继续调用await(剩余超时时间会自动计算),直到条件满足或者超时。

修改后的代码实现

将原有的waitForever方法修改为带5秒超时的版本,同时保留应对虚假唤醒的循环逻辑:

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Scratch {
    private final Lock lock = new ReentrantLock();
    private final Condition flagSet = lock.newCondition();
    private boolean flag;

    boolean waitWithTimeout() throws InterruptedException {
        lock.lock();
        try {
            // 循环检查条件,未满足则继续等待(最多累计5秒)
            while (!flag) {
                // await返回false代表超时,直接退出循环
                if (!flagSet.await(5, TimeUnit.SECONDS)) {
                    break;
                }
            }
            // 返回最终条件是否满足
            return flag;
        } finally {
            lock.unlock();
        }
    }

    void setFlag() {
        lock.lock();
        try {
            flag = true;
            System.out.println("Flag set to true");
            flagSet.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        var scratch = new Scratch();
        var executor = Executors.newSingleThreadScheduledExecutor();
        // 这里把延迟改成3秒,测试条件满足的情况;改成6秒则测试超时情况
        executor.schedule(scratch::setFlag, 3, TimeUnit.SECONDS);
        System.out.println("Waiting for flag (max 5 seconds)...");
        boolean flagMet = scratch.waitWithTimeout();
        if (flagMet) {
            System.out.println("Finished waiting: flag was set");
        } else {
            System.out.println("Finished waiting: timeout reached");
        }
        executor.shutdownNow();
    }
}

关键修改点

  1. 将flagSet.await()替换为flagSet.await(5, TimeUnit.SECONDS),并接收返回值:
    • 返回true:表示在超时前被唤醒,需要重新检查条件
    • 返回false:表示已超时,直接退出循环
  2. 保留while (!flag)的循环逻辑:无论正常唤醒还是虚假唤醒,只要条件不满足,就继续等待(剩余超时时间会由Condition内部自动维护)
  3. 方法返回boolean值,方便调用者判断是条件满足还是超时退出

内容的提问来源于stack exchange,提问作者David O'Loughlin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 08:35:13