I write the below code to test when will the thread is awake when it is waiting for a Condition
object.
- But I find I have to unlock after I call
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
andunlock
,say I sleep 10 seconds, what exactly the time java signal the other thread? Is there a another background thread who is working between wesignal
andunlock
?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:
- the API would become confusing: there would be more than one method releasing the lock;
- the APi would become more restrictive and preclude any use cases where the thread wants to do something more before releasing the lock, such as atomically issuing more signals.
来源:https://stackoverflow.com/questions/27058828/why-await-of-condition-releases-the-lock-but-signal-does-not