I write the below code to test when will the thread is awake when it is waiting for a Condition
object.
signal()
. Lock is not release by this method, while await() will release this lock . This is from Condition#await
The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
And this is from Conditon#signal
Wakes up one waiting thread.
If any threads are waiting on this condition then one is selected for waking up. That thread must then re-acquire the lock before returning from await.
But in my code, this is not true, until we unlock the lock. Why it is design like this? Since in my opinion, when we decide to to signal the others, we should not hold the lock any more,am I wrong?
Since we can do many things between calling signal
and unlock
,say I sleep 10 seconds, what exactly the time java signal the other thread? Is there a another background thread who is working between we signal
and 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();
}
}
OUTPUT:
THREAD ID 9-------working --------
------singnall--------
------unlock--------
THREAD ID 10-------working --------
------singnall--------
------unlock--------
You have missed this sentence in Contition#await
:
In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.
In other words, you must explicitly release the lock after await
, just as with signal
.
Why this mechanism is sound: if you first released the lock, then signal
ed, you'd be open to race conditions where other threads made changes between releasing the lock and the signal reaching a parked thread. The way the mechanism works, first a definite thread is chosen to be awoken by the signal, then it waits for the lock, then the signaling thread releases it, then the awoken thread goes on.
You might argue that signal
could do all of this internally, but then:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With