Lock/Condition is await notification mechanism provided in Java. Using await and signal of Condition is similar to synchronized based wait and notify, both of which implement wait notification mechanisms.
However, there are still differences in the way the two are used and implemented. Such as:
- The wait notification mechanism involves synchronous queues and wait queues, of objects
wait/notify
You can only have one wait queue, and a Condition can have multiple wait queues. wait/notify
The wait queue management of Condition is controlled by the JVM, while Condition is implemented by JDK/JUC.
wait/notify
Synchronous queue flow chart:
Flow chart of Condition synchronous queue:
The Lock Condition example code is as follows:
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread t1 = new Thread(() -> {
lock.lock();
try {
condition.await();
System.out.println(Thread.currentThread().getName() + " await ok");
} catch (InterruptedException ignore) {
} finally{ lock.unlock(); }},"t1");
t1.start();
Thread t2 = new Thread(() -> {
lock.lock();
try {
// Move the wait queue node to the AQS synchronization queue (tail)
condition.signal();
System.out.println(Thread.currentThread().getName() + " signal ok");
} finally {
// Wake up the blocked thread in the AQS synchronization queuelock.unlock(); }},"t2");
t2.start();
}
Copy the code
Note that await and signal must be in lock to ensure atomicity of the operation wait queue and synchronization queue, and await has a release state, which is an operation of unlock.
Let’s examine the await and signal flow of Condition using the above example code. For thread T1, execution to the await method adds a node to the wait queue, then releases the current state, wakes up other threads, and finally blocks itself, waiting to be woken up.
public final void await(a) throws InterruptedException {
// Add a node to the wait queue. This method does not consider scenarios, so it needs to be in lock
Node node = addConditionWaiter();
// Releasing the current AQS state wakes up the waiting thread in the synchronization queue
int savedState = fullyRelease(node);
int interruptMode = 0;
while(! isOnSyncQueue(node)) {The current thread is blocked, waiting to be woken up
LockSupport.park(this);
if((interruptMode = checkInterruptWhileWaiting(node)) ! =0)
break;
}
// Wake up and get state again. Exit after successfully obtaining state
if(acquireQueued(node, savedState) && interruptMode ! = THROW_IE) interruptMode = REINTERRUPT;if(node.nextWaiter ! =null) // clean up if cancelled
unlinkCancelledWaiters();
if(interruptMode ! =0)
reportInterruptAfterWait(interruptMode);
}
Copy the code
When another thread executes signal, it moves the node from the waiting queue to the synchronization queue, and finally wakes up the synchronization queue thread with unlock.
public final void signal(a) {
// The current occupation of state does not throw an exception
if(! isHeldExclusively())throw new IllegalMonitorStateException();
// Start to wake up the first node
Node first = firstWaiter;
if(first ! =null)
doSignal(first);
}
// Wake up the first Node in node. CONDITION, since some nodes may be in other states due to timeout, there is no need to wake up
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while(! transferForSignal(first) && (first = firstWaiter) ! =null);
}
final boolean transferForSignal(Node node) {
// reset node state to enter synchronization queue soon
if(! compareAndSetWaitStatus(node, Node.CONDITION,0))
return false;
If the state of the previous node is >0, yes
Node p = enq(node);
int ws = p.waitStatus;
// ws>0 indicates that the status of the previous node is incorrect and needs to be set to SIGNAL to wake up the newly added node
if (ws > 0| |! compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread);// If the CAS configuration fails, you can only wake it up first
return true;
}
Copy the code
SignalAll is the same as signal. The Condition interface method is await.
So far, the Lock Condition related core code has been analyzed, because Condition is related to AQS, Object.wait/signal, so the information about AQS can refer to how AQS controls threads. Object. Wait/Signal can be referred to the principle of synchronized and Object. Wait /notify.
Recommended reading
- How does AQS control threads
- A brief introduction to the principle of synchronized and Object.wait/notify
- The states of Java threads
- How to gracefully print ABC from 3 threads
- DDD domain concepts
- How to solve the problem of large paging query
- From intrusive Service governance to Service Mesh