Each period summarizes a small knowledge point and related interview questions, hey hey, and we learn together.

There is a class in GUC that we use less often, but it is an indispensable member of many classes. He is Condition.

True or false: True or false: True or false Condition acts as a multithreaded shared identifier that blocks when true passes and when false waits.

1. Use of Condition

You can see how to use it in the following code.

// thread 1
System.out.println("1 am thread 1 start");
condition.await();/ / blocking
System.out.println("1 am thread 1 end");

// thread 2
System.out.println("1 am thread 2");
condition.signal():/ / wake
Copy the code

Suppose thread 1 and thread 2 execute concurrently. The output after execution would be:

1 am thread 1 start
1 am thread 2
1 am thread 1 end
Copy the code

Similar to wait(),notify() for an Object. The only difference is that the Condition does not require the Synchronize modification first to invoke the blocking method. Does that make it easier to use? The judgement of empty and full in the blocking queue is realized based on Condition, which can guarantee the order of notification.

2. Principle of Condition

A Condition instance is essentially bound to a lock. To get a Condition instance of a particular Condition instance, use its newCondition() method.

   final Lock lock = new ReentrantLock();
   // Need to bind to lock
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 
Copy the code

2.1 Condition API

Modifier and Type Method and Description
void await()Causes the current thread to wait to signal orinterrupted 。
boolean await(long time, TimeUnit unit)Causes the current thread to wait until signaled or interrupted, or the specified wait time has elapsed.
long awaitNanos(long nanosTimeout)Causes the current thread to wait until signaled or interrupted, or the specified wait time has elapsed.
void awaitUninterruptibly()Causes the current thread to wait until signaled.
boolean awaitUntil(Date deadline)Causes the current thread to wait until signaled or interrupted, or until a specified deadline has passed.
void signal()Wake up a waiting thread.
void signalAll()Wake up all waiting threads.

2.1 Condition to realize

Initialization method:

final ConditionObject newCondition(a) {
  ConditionObject is the inner class of AQS, from which attributes and methods from the outer class can be called
  return new ConditionObject();
}
Copy the code

Let’s first look at the await method, which blocks wait:

public final void await(a) throws InterruptedException {
    If the current thread is interrupted, InterruptedException is thrown
    if (Thread.interrupted())
        throw new InterruptedException();
    Condition = Condition; Condition = Condition; Condition = Condition; Condition = Condition
    Node node = addConditionWaiter();
    // Release with node's current state value; Return to save state
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // Is the queue synchronized? IsOnSyncQueue returns true if the next Node is not empty, meaning that thread blocking is performed on the first non-LCH Node.
    while(! isOnSyncQueue(node)) {// The current thread is blocked
        LockSupport.park(this);
        // Check whether there is an interruption
        if((interruptMode = checkInterruptWhileWaiting(node)) ! =0)
            break;
    }
    // Interrupt status processing
    if(acquireQueued(node, savedState) && interruptMode ! = THROW_IE) interruptMode = REINTERRUPT;// Node cleanup
    if(node.nextWaiter ! =null) // clean up if cancelled
        unlinkCancelledWaiters();
    // 0 is the default state
    if(interruptMode ! =0)
        / / the interrupt processing
        reportInterruptAfterWait(interruptMode);
}

private Node addConditionWaiter(a) {
    Node t = lastWaiter;
    // If lastWaiter is cancelled, clean out.
    if(t ! =null&& t.waitStatus ! = Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; }// Create a Node in condition
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

final int fullyRelease(Node node) {
    boolean failed = true;
    try {
        int savedState = getState();
        if (release(savedState)) {
            failed = false;
            return savedState;
        } else {
            throw newIllegalMonitorStateException(); }}finally {
        if(failed) node.waitStatus = Node.CANCELLED; }}Copy the code

Let’s see how signal wakes up Node:

public final void signal(a) {
    GetExclusiveOwnerThread () == thread.currentThread ();
    if(! isHeldExclusively())throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    // Nodes that are waiting need to be woken up
    if(first ! =null)
        doSignal(first);
}

private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    // Move the node from conditional queue to synchronous queue.
    } while(! transferForSignal(first) && (first = firstWaiter) ! =null);
}


final boolean transferForSignal(Node node) {
    /* * If cannot change waitStatus, the node has been cancelled. */
    if(! compareAndSetWaitStatus(node, Node.CONDITION,0))
        return false;

    /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0| |! compareAndSetWaitStatus(p, ws, Node.SIGNAL))// unpark wakes up the thread
        LockSupport.unpark(node.thread);
    return true;
}
Copy the code

Condition 3

3.1. What is Java false wake up and how to avoid false wake up?

False awaken

When a condition is met, many threads are awakened, but only some of them are useful awakenings. The rest are useless

For example, if an item has no goods and suddenly enters an item, all threads are awakened, but only one person can buy it, so everyone else is falsely awakened and cannot acquire the lock of the object

How to avoid false awakenings

When all threads are awakened, the critical condition is checked using while judgment, so that when the thread is awakened, the condition can be checked again.

3.2. When are Mutex and BooleanLatch used

Mutex: This is a non-reentrant Mutex class that uses zero to indicate unlocked status and one to indicate locked status. While non-reentrant locking does not strictly require logging the current owner thread, it nevertheless makes usage easier to monitor. It also supports conditions and exposes one of the instrumentation methods

BooleanLatch: This is a latch class similar to CountDownLatch, except that it only needs a signal to trigger

3.3 Differences between CLH lock and MCS lock

  • In terms of code implementation, CLH is much simpler than MCS.
  • In terms of spin conditions, CLH spins on attributes of the precursor node, while MCS spins on local attribute variables.
  • From the view of linked list queue, CLHNode does not directly hold the precursor node, CLH lock release only need to change its own attributes; McSnodes directly hold their successor nodes. The MCS lock release requires changing the properties of the successor nodes.
  • CLH lock release only needs to change its own properties, MCS lock release requires to change the properties of subsequent nodes

3.4 What are the states of Node

  • CANCELLED(1) : indicates that the current node has been CANCELLED. When timeout or interrupted (in response to an interrupt), a change is triggered to this state, and the node will not change after entering this state.
  • SIGNAL(-1) : indicates that the successor node is waiting for the current node to wake up. When a successor node joins the queue, its status is updated to SIGNAL.
  • CONDITION(-2) : indicates that the node is waiting on CONDITION. When another thread calls CONDITION signal(), the node in CONDITION will be transferred from the waiting queue to the synchronization queue, waiting for the synchronization lock.
  • PROPAGATE(-3) : In the shared mode, not only does the previous parent node wake up the subsequent one, but it may also wake up the subsequent one.
  • 0: indicates the default state when a new node joins the queue.

Scan the QR code to follow the public account “Ape Must Pass”

Answer the “interview questions” and collect them yourself.

Wechat group for discussion, please add wechat account: zyhui98, note: interview questions add group

This article is published by YBG. Unauthorized reprint is prohibited. Violators are subject to legal liability