Java Condition.await()在其锁调用unlock()之前不会发出信号



Condition.await():的Java文档

与此Condition关联的锁被原子释放出于线程调度目的,当前线程被禁用,并且处于休眠状态,直到发生以下四件事之一:

  • 其他一些线程为此Condition调用signal方法

。。。

我写了一个测试程序,看看线程1调用Condition.await()并被阻止后,线程2调用Condition.signal()

我预计线程1应该立即从await()返回并继续。

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.*;
public class TestThreadCondition {
public static void main(String[] args) throws InterruptedException {
Lock rLock = new ReentrantLock();
Condition cond = rLock.newCondition();
AtomicBoolean aBool = new AtomicBoolean(true);
Thread t1 = new Thread(new Runnable() {
@Override public void run() {
try {
rLock.lock();
System.out.println("(Step 1) Thread 1 locks and sleeps 1s");
Thread.sleep(1000);
while (aBool.get()) {
System.out.println("(Step 3) Thread 1 enters while loop");
cond.await();
System.out.println("(Step 5) Thread 1 got signal");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override public void run() {
try {
Thread.sleep(300);
System.out.println("(Step 2) Thread 2 also requires lock, blocked");
rLock.lock();
System.out.println("(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal");
cond.signal(); // I hope this would signal "t1" and t1 will enter (Step 5) immediately.
System.out.println("(Step 6) Thread 2 sleeps 3s and set aBool");
Thread.sleep(3000);
aBool.compareAndSet(true, false);
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
System.out.println("(Step 7) unlock");
}
}
});
t2.start();
t1.join();
t2.join();
}
}

期望该程序将运行并打印

Step1->Step2->Step3->Step4->Step5->Step6->Step7.

实际结果是:

(Step 1) Thread 1 locks and sleeps 1s
(Step 2) Thread 2 also requires lock, blocked
(Step 3) Thread 1 enters while loop
(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal
(Step 6) Thread 2 sleeps 3s and set aBool
(Step 7) unlock
(Step 5) Thread 1 got signal

步骤5是在第6步

第7步这似乎与Javadoc的解释相冲突,正如我在开头所说的那样。如何理解我的代码的行为?

在代码打印时

(Step 5) Thread 1 got signal

Thread1已退出等待方法。如果没有获得锁,它就不可能走到这一步。因此,如果另一个线程仍然有锁,那么这种情况自然不会发生。

因此,您的代码不是一个好的测试,我们不知道信号是否被延迟到锁被释放,或者信号是否早于此发生,线程1被唤醒,但在获取锁时被阻止。

在与内部锁类似的情况下,apidoc中详细说明了notify被延迟,直到通知线程释放其锁。等待线程无论如何都要到那时才能执行操作。如果这里也出现同样的情况,那也就不足为奇了。在任何情况下,javadoc中都没有矛盾,唤醒和获取锁是两件不同的事情。

最新更新