Reentrantlock code analysis: reentrantlock. lockinterruptibly

Source: Internet
Author: User

Reentrantlock. lockinterruptiblyWhen waiting, other threads are allowed to call the thread. interrupt method of the waiting thread to interrupt the waiting thread and return directly. In this case, an interruptedexception is thrown instead of obtaining the lock. The reentrantlock. Lock method does not allow thread. Interrupt interruption. Even if thread. isinterrupted is detected, it will continue to try to obtain the lock. If the lock fails, it will continue to sleep. Only after the lock is successfully obtained, the current thread is set to interrupted.

Then how does lockinterruptibly achieve this?

Public   Void Lockinterruptibly () Throws Interruptedexception {
Sync. acquireinterruptibly ( 1 );
}

Called hereAbstractqueuedsynchronizer. acquireinterruptiblyMethod. If the thread has been interrupted, an exception is thrown directly. Otherwise, the lock is obtained. If the thread failsDoacquireinterruptibly

 

Abstractqueuedsynchronizer. acquireinterruptibly (INT Arg)   /**
* Acquires in exclusive mode, aborting if interrupted.
* Implemented by first checking interrupt status, then invoking
* At least once { @ Link # Tryacquire}, returning on
* Success. Otherwise the thread is queued, Possibly repeatedly
* Blocking and unblocking, invoking { @ Link # Tryacquire}
* Until success or the thread is interrupted. This method can be
* Used to implement method { @ Link Lock # lockinterruptibly }.
*
* @ Param Arg the acquire argument. This value is conveyed
*{ @ Link # Tryacquire} but is otherwise uninterpreted and
* Can represent anything you like.
* @ Throws Interruptedexception if the current thread is interrupted
*/
Public   Final   Void Acquireinterruptibly ( Int Arg) Throws Interruptedexception {
If (Thread. interrupted ())
Throw   New Interruptedexception ();
If ( ! Tryacquire (ARG ))
Doacquireinterruptibly (ARG );
}

Abstractqueuedsynchronizer. doacquireinterruptiblyBasically equivalent to the previousAcquirequeued,The key difference lies in detectingInterruptedAfter processing,AcquirequeuedSimply record the occurrence of the interruption, and then try to obtain the lock like nobody else. If it fails, it will sleep. WhileDoacquireinterruptiblyIf an interruption is detected, the system exits the loop and throwsInterruptedexceptionException.

 

Abstractqueuedsynchronizer. doacquireinterruptibly (INT Arg) /**
* Acquires in exclusive interruptible mode.
* @ Param Arg the acquire argument
*/
Private   Void Doacquireinterruptibly ( Int Arg)
Throws Interruptedexception {
Final Node = Addwaiter (node. Exclusive );
Try {
For (;;){
Final Node P = Node. predecessor ();
If (P = Head && Tryacquire (ARG )){
Sethead (node );
P. Next =   Null ; // Help GC
Return ;
}
/*
AcquirequeuedCode:
If (shouldparkafterfailedacquire (p, node )&&
Parkandcheckinterrupt ())
Interrupted = true;
*/
If (Shouldparkafterfailedacquire (p, node) &&
Parkandcheckinterrupt ())
Break ;
}
} Catch (Runtimeexception ex ){
Cancelacquire (node );
Throw Ex;
}
// Arrive here only if interrupted
// Cancels the lock acquisition attempt and removes the current node from the waiting queue.
Cancelacquire (node );
Throw   New Interruptedexception ();
}

Before an exception is thrown,DoacquireinterruptiblyI also did one thing,Cancelacquire.CancelacquireSome details are worth noting. See the author's notes in the code.

 

 

Abstractqueuedsynchronizer. Cancelacquire (node) /**
* Cancels an ongoing attempt to acquire.
*
* @ Param Node the node
*/
Private   Void Cancelacquire (node ){
// Ignore If node doesn' t exist
If (Node =   Null )
Return ;

Node. Thread= Null;

// Skip canceled predecessors
// The header node will not be in the waiting status, so it will not be cancel, so a node can be found here without worrying about null
Node Pred = Node. Prev;
While (Pred. waitstatus >   0 )
Node. Prev = PRED = Pred. Prev;

//Getting this before setting waitstatus ensures staleness
Node prednext=Pred. Next;
//Can use unconditional write instead of CAS here
Node. waitstatus=Node. cancelled;

// If we are the tail, remove ourselves
If (Node = Tail && Compareandsettail (node, Pred )){
Compareandsetnext (Pred, prednext, Null );
} Else {
// If "active" Predecessor found...
If (PRED ! = Head
&& (Pred. waitstatus = Node. Signal
| Compareandsetwaitstatus (Pred, 0 , Node. Signal ))
&& Pred. Thread ! =   Null ){

// If successor is active, set predecessor's next link
Node next = Node. Next;
If (Next ! =   Null   && Next. waitstatus <=   0 )
Compareandsetnext (Pred, prednext, next );
} Else {
/* If unparksuccessor is not called here, if after interrupted, the lock is released before waitstatus is set to cancelled, And the thread is awakened, the unparksuccessor of the lock release thread cannot play the expected role. Therefore, you need to call unparksuccessor here. even if the thread holding the lock does not release the lock at this time, there will be no serious consequences. The unpark thread will continue to park after the lock fails to be obtained. */
Unparksuccessor (node );
}
Node. Next = Node; // Help GC
}
}

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.