About High concurrency (9) implementation of several spin locks (4)

Source: Internet
Author: User

This article describes how to implement the time limit queue lock. The lock definition in the Java concurrent package contains the Time Limit lock interface:

public interface Lock {    void lock();    void lockInterruptibly() throws InterruptedException;    boolean tryLock();    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;    void unlock();    Condition newCondition();}

Trylock is the interface for implementing locks. It supports time-limited operations and interrupt operations. These two features are very important. They can prevent deadlocks or cancel locks when deadlocks occur.


Because of these two features, the queue lock node must support the "Exit queue" mechanism. That is to say, when a timeout or thread is interrupted, the thread can exit the queue from the queue, other nodes are not affected. Several queue locks previously implemented do not support the exit mechanism. Once the threads in the queue are blocked for a long time, all subsequent threads will be passively blocked.


Let's look at the implementation of a time-limited queue lock, which has several points:

1. Define a shared available node. When the prenode of a node points to available, it indicates that the node obtains the lock.

2. the qnode node maintains a prenode reference. This reference only points to available when the lock is obtained, or points to the previous node when the lock times out. Other values are null when waiting for the lock, once a node times out, it needs to point its subsequent nodes to its precursor node. Therefore, only the prenode value (except for the value pointing to an available node) will be set when the node times out ).

3. Use a atomicreference atomic variable tail to form a virtual one-way linked list structure. The getandset operation of tail returns the reference of the previous node, which is equivalent to obtaining the precursor node. After the lock is obtained, the reference of the precursor node is released, and the precursor node can be recycled by GC.

4. Supports the interrupt operation. thread. isinterrupted () can obtain the thread interrupt information. Once the thread interrupt information is obtained, an interrupt exception is thrown. Note that when thread interruption information is sent, it does not require the thread to be interrupted immediately. Instead, it notifies the thread of the information to be interrupted and the program controls the location of the thread interruption.

5. because the thread has only one threadlocal mynode variable pointing to its own node, the method of getting a lock is used every time a new node is created and set to the thread, to avoid the impact of unlock on node operations on the status of subsequent nodes, the thread can also obtain the lock multiple times. Here, we can consider maintaining two threadlocal references like clhlock. When releasing the lock, we will point the reference of mynode to an unused precursor node, so as to avoid unnecessary new operations.


Package COM. ZC. lock; import Java. util. concurrent. timeunit; import Java. util. concurrent. atomic. atomicreference;/*** time queue lock, supporting trylock timeout operation * qnode maintains a pointer prenode to the forward node. When prenode = available, the lock has been released. When prenode = NULL, it indicates waiting for the lock * tail maintains a virtual linked list through tail. the getandset method obtains the previous node and spin the previous node. When the lock is released, the prenode of the previous node is = avaiable, automatically notifies the next node to obtain the lock * When a node times out or is interrupted, its precursor node is not empty. When the subsequent node sees that its precursor node is not empty and is not available, it will know that the node has exited and will skip it * When the node gets the lock and enters the critical section, its Precursor node can be recycled ***/public class timeoutlock implements trylock {// declared as a static variable to prevent temporary collection of Private Static final qnode available = new qnode (); // The Atomic variable points to the private atomicreference <qnode> tail; threadlocal <qnode> mynode; Public timeoutlock () {tail = new atomicreference <qnode> (null ); mynode = new threadlocal <qnode> () {protected qnode initialvalue () {return ne W qnode () ;}}}@ overridepublic void lock () {// different from clhlock, each time a node is created and set to the thread, the purpose is to support the same thread to obtain the lock Multiple times without affecting the status of other nodes in the chain. // clhlock does not need to be created every time because it uses two pointers, A forward node. After the precursor node is released, it can be recycled. // Clhlock sets mynode to an invalid precursor node each time the lock is released. It is also used to support the same thread to obtain the lock Multiple times without affecting other nodes. qnode node = new qnode (); mynode. set (node); qnode pre = tail. getandset (node); If (pre! = NULL) {// The previous node spin. When the current node is available, it obtains the lock while (PRE. prenode! = Available) {}}@ overridepublic void unlock () {qnode node = mynode. get (); // CAS operation. If it is true, it indicates that it is a unique node and can be released directly. Otherwise, point prenode to availableif (! Tail. compareandset (node, null) {node. prenode = available ;}@ override // timeunit only supports millisecond public Boolean trylock (long time, timeunit unit) throws interruptedexception {If (thread. interrupted () {Throw new interruptedexception ();} Boolean isinterrupted = false; long starttime = system. currenttimemillis (); long duration = timeunit. milliseconds. convert (time, Unit); // Note: Each trylock requires a new node, so that the same thread can obtain the lock multiple times. If each thread uses the same node, the qnode = new qnode (); mynode of other nodes in the chain will be affected. set (node); // try to obtain the lock qnode pre = tail once. getandset (node); // The first or previous node is a node that has been unlocked, pre = available indicates that the lock if (pre = NULL | pre = available) {return true;} // spin the while (system. currenttimemillis ()-starttime <duration )&&! Isinterrupted) {qnode predprenode = pre. prenode; // indicates that the previous node has released the lock and set the prenode domain. Otherwise, the prenode domain is empty if (predprenode = available) {return true;} // when preprenode! = NULL, there are only two cases: It times out or is interrupted. // Skip a node whose preprenode is not empty and continue to spin its next node else if (predprenode! = NULL) {pre = predprenode;} If (thread. interrupted () {isinterrupted = true ;}// timeout or interrupted, you must set the node's front-end node not to be empty. prenode = pre; If (isinterrupted) {Throw new interruptedexception ();} return false;} public static class qnode {volatile qnode prenode;} Public String tostring () {return "timeoutlock ";}}

Timeoutlock has all the features of clhlock, such as zero hunger. First, we should provide service fairness, spin on multiple shared variables, and control reasonable cache consistent traffic, it also supports limited-time and interrupted operations.

A fixed template is used to prevent the lock from being used incorrectly.


Lock lock = ...;if (lock.tryLock()) {     try {     // manipulate protected state     } finally {        lock.unlock();     }} else {    // perform alternative actions}

Similarly, the test cases that we used to verify the lock correctness are also valid for timeoutlock. Here we will not repeat the code.


Reprinted please indicate Source: http://blog.csdn.net/iter_zc








About High concurrency (9) implementation of several spin locks (4)

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.