"Dead java Concurrency"-----j.u.c aqs: Blocking and waking threads

Source: Internet
Author: User
Tags prev

All source code for this blog is from JDK 1.8

When the thread gets the synchronization state, if the acquisition fails, the CLH synchronization queue is added, and the synchronization state is continuously obtained by spinning, but in the process of spin, it is necessary to determine whether the current thread needs to block, and its main method is acquirequeued ():

if (shouldParkAfterFailedAcquire(p, node) &&                    parkAndCheckInterrupt())                    true;

With this code we can see that after the failure to get the synchronization state, the thread does not immediately block, need to check the state of the thread, check the state of the method is Shouldparkafterfailedacquire (node pred, node node) method, This method mainly depends on the precursor node to determine whether the current thread should be blocked, the code is as follows:

    Private Static Boolean Shouldparkafterfailedacquire(Node pred, node node) {//Precursor node        intWS = Pred.waitstatus;//The status is signal, indicating that the current thread is in a wait state and put it back directly to True        if(ws = = node.signal)return true;///precursor node status > 0, then cancelled, indicating that the node has timed out or been interrupted and needs to be canceled from the synchronization queue        if(WS >0{do {Node.prev = pred = Pred.prev; } while(Pred.waitstatus >0);        Pred.next = node; }//Precursor node status is condition, propagate        Else{Compareandsetwaitstatus (pred, WS, node.signal); }return false; }

This code primarily checks whether the current thread needs to be blocked, as follows:

    1. If the current thread's predecessor node state is sinnal, it indicates that the current thread needs to be blocked, call the Unpark () method to wake up, return true directly, and the current thread is blocked
    2. If the current thread's predecessor node status is cancelled (ws > 0), it indicates that the thread's precursor node has waited for a timeout or is interrupted, then the precursor node needs to be removed from the CLH queue until it goes back to the predecessor node State <= 0, returning false
    3. If the precursor node is non-sinnal, non-cancelled, the precursor node is set to Sinnal by CAs, which returns false

If the Shouldparkafterfailedacquire (node pred, node node) method returns True, the Parkandcheckinterrupt () method is called to block the current thread:

    privatefinalbooleanparkAndCheckInterrupt() {        LockSupport.park(this);        return Thread.interrupted();    }

The Parkandcheckinterrupt () method mainly suspends the current thread, blocking the thread's call stack and returning the current thread's interrupt state. Inside it is the park () method that calls the Locksupport tool class to block the method.

After the thread releases the synchronization state, it needs to wake the thread's successor:

    publicfinalbooleanrelease(int arg) {        if (tryRelease(arg)) {            Node h = head;            ifnull0)                //唤醒后继节点                unparkSuccessor(h);            returntrue;        }        returnfalse;    }

Call Unparksuccessor (node node) to wake the successor:

    Private void Unparksuccessor(Node node) {//Current node status        intWS = Node.waitstatus;//Current status < 0 set to 0        if(WS <0) Compareandsetwaitstatus (node, WS,0);//Successor node of the current nodeNode s = node.next;//successor node is null or its status > 0 (timed out or interrupted)        if(s = =NULL|| S.waitstatus >0) {s =NULL;//from the tail node to find available nodes             for(Node t = tail; t! =NULL&& T! = node; t = T.prev)if(T.waitstatus <=0) s = t; }//Wake up subsequent nodes        if(s! =NULL) Locksupport.unpark (S.thread); }

There may be a case where the successor of the current thread is null, timed out, interrupted, and if this is the case, you need to skip that node, but why start with the tail tail node instead of starting with Node.next? The reason is that node.next can still be null or canceled, so use the tail backtracking method to find the first available thread. Finally, call Locksupport's Unpark (thread thread) method to wake the thread.

Locksupport

From the above I can see that when it is necessary to block or wake up a thread, Aqs is done using the Locksupport tool class.

Locksupport is the basic thread blocking primitive used to create locks and other synchronization classes

Each thread that uses Locksupport is associated with a license, and if the license is available and can be used in the process, calling Park () will return immediately, otherwise it may be blocked. If the license is not yet available, you can call Unpark to make it available. However, note that the license is not reentrant, that is, the park () method can only be called once, otherwise it will be blocked.

Locksupport defines a series of methods that start with Park to block the current thread, Unpark the thread thread method to wake up a blocked thread. As follows:

The blocker parameter of the Park (object blocker) method is primarily used to identify the object that the current thread is waiting for, which is used primarily for troubleshooting and system monitoring.

The park method and the Unpark (thread thread) are paired, and Unpark must be executed after park executes, not to mention that the Unpark thread will always block without calling, and park has a method with a timestamp (Parknanos (Long Nanos): Disables the current thread for thread scheduling and waits up to the specified wait time, unless the license is available.

The source code for the park () method is as follows:

    publicstaticvoidpark() {        UNSAFE.park(false0L);    }

Unpark (thread thread) method source code is as follows:

    publicstaticvoidunpark(Thread thread) {        ifnull)            UNSAFE.unpark(thread);    }

As can be seen from the above, the implementation of the internal is through the unsafe (sun.misc.Unsafe unsafe) to achieve, which is defined as follows:

publicnativevoidpark(booleanlong var2);publicnativevoidunpark(Object var1);

All two are native local methods. Unsafe is a dangerous class that is primarily used to perform low-level, unsafe collection of methods. Although this class and all methods are public, the use of this class is still limited, and you cannot use the class directly in your own Java program, because only the code of the message can obtain an instance of the class.

Resources
    1. Fang Fei: "The Art of Java concurrent programming"
    2. Basic use of Locksupport Park and Unpark, and responsiveness to thread interrupts

"Dead java Concurrency"-----j.u.c aqs: Blocking and waking threads

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.