我编写下面的代码来测试线程在等待Condition
对象时何时处于唤醒状态。
signal()
后我必须解锁。此方法不会释放锁定,而await()将释放此锁定。 与此条件关联的锁是原子释放,并且当前线程因线程调度而被禁用,并且在发生以下四种情况之一之前处于休眠状态:
这是来自Conditon#signal
唤醒一个等待线程。
如果任何线程正在等待这种情况,则选择一个线程进行唤醒。然后该线程必须重新获取锁 等待回来。
但在我的代码中,这不是真的,直到我们解锁。为什么这样设计?因为在我看来,当我们决定向其他人发出信号时,我们不应再持有锁,我错了吗?
因为我们可以在调用signal
和unlock
之间做很多事情,比如说我睡了10秒,java究竟是什么时候发出了另一个线程的信号?还有另一个后台主题是我们signal
和unlock
之间的工作吗?
public class WorkerThread extends Thread{
@Override
public void run() {
Monitor.lock.lock();
while (!Monitor.isConditionTrue){
try {
Monitor.condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("THREAD ID "+this.getId()+"-------working --------");
System.out.println("------singnall--------");
Monitor.isConditionTrue=true;
Monitor.condition.signal();
try {
Thread.sleep(3000);//here, the thread is sleeping while another thread is not awaken since the lock is not releases
System.out.println("------unlock--------");
Monitor.lock.unlock();//now the other thread is awaken, if I do not explicitly unlock , no thread will be awaken.
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Monitor {
static ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
static volatile boolean isConditionTrue = true;
public static void main(String args[]) {
Thread t1 = new WorkerThread();
Thread t2 = new WorkerThread();
t1.start();
t2.start();
Thread.sleep(2000);
lock.lock();
isConditionTrue=true;
condition.signalAll();
lock.unlock();
}
}
输出:
THREAD ID 9-------working --------
------singnall--------
------unlock--------
THREAD ID 10-------working --------
------singnall--------
------unlock--------
答案 0 :(得分:8)
您错过了Contition#await
中的这句话:
在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时,保证保持此锁定。
换句话说,您必须在await
之后明确释放锁定,就像使用signal
一样。
为什么这个机制是合理的:如果你第一次释放锁,然后signal
ed,你就会对竞争条件开放,其他线程在释放锁和信号到达停放线程之间做出了改变。机制的工作方式,首先选择一个确定的线程被信号唤醒,然后它等待锁定,然后信号线程释放它,然后唤醒线程继续。
你可能会认为signal
可以在内部完成所有这些,但随后: