如果我们在 Java 中被当前线程多次调用 condition.await() 会发生什么

问题描述

我想了解当我们执行以下代码片段时到底发生了什么。

一个线程执行 someMethod() 并遇到 while 循环时,如果它一次又一次地调用 await 方法会发生什么? Condition/reentrantlock 如何存储/维护线程上下文?

另外,一旦一个线程调用了await(),就意味着它释放了当前的锁,进入了等待状态。这是否意味着另一个线程可以获得锁?如果是这样,围绕await()方法编写while循环有什么用?

Lock lock = new reentrantlock();
Condition condition = lock.newCondition();
...
...
    public void someMethod() {
        lock.lock();
        try {
            for (int i = 2; i < n; i = i + 2) {
                while (state != 2) {
                    condition.await();
                }
                printNumber.accept(i);
                r.run();
                state = 0;
                condition.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }

如果我的理解有误,请指正。提前致谢。

解决方法

该等待循环的重点显然是等到状态为 2。从 await 调用中醒来仅意味着您已经醒来。这并不意味着状态为 2。

这个逻辑和我半夜等起来,看看时钟,决定回去睡觉的时候是一样的。 :-)

请注意 documentation for Condition 明确指出可能会发生虚假唤醒。这意味着任何不检查实际所需状态的 Condition.await 的使用几乎肯定有错误。

与此同时,这段代码似乎有缺陷。您知道当线程在 signalAll 中等待时您不会执行 await 调用,对吗?因为线程在 await 中等待。需要有一些其他线程,执行不同的代码,可以发出条件信号,以使该线程摆脱等待。


您的问题:

我想了解当我们执行以下操作时真正会发生什么 代码片段。

在显示的代码中,线程永远处于 await 调用中,因为没有显示可以唤醒它的代码。

(根据文档,存在虚假唤醒的可能性,如果发生这种情况,while 循环会将线程重新置于等待状态,因为等待的内容不会改变。)

>

关于“一次又一次地调用 await”——好吧,你不能在等待时调用 await——因为当你不跑步时,你无处可调用任何东西。所以第一次调用和后续调用之间没有区别。在每种情况下,调用线程都会进入休眠状态,直到随后发出信号。

关于锁定 - 在等待时释放锁定,并在唤醒时重新获取。这是实际需要;大概在你的例子中,锁保护对“状态”的访问,任何想要修改状态和唤醒服务员的代码最好在锁的保护下这样做。