[Java Concurrency] AQS (1) - Concurrent three tricks

Set their own goals can not start collapsed ah, tomorrow a holiday, so I quickly began to update the first article in the series of concurrent programming Java (precisely, is the second, because the front also wrote FutureTask source interpretation) , AQS is the first article in the series. In fact, about AQS series already written, but has been repeatedly modified and not made up, because I want my article is valuable information. As a software engineering cubs oriented search engine programming, I will contact with a lot of useless information every day, so faith care network, the idea is everyone's responsibility, for the article to the issue in the future, I will examine the content check

 

No bullshit, say real information into the garbage, and the following entry to the topic

 

1. What is the AQS

AQS AbstractQueuedSynchronizer full name (referred to later have to AQS), called an abstract translation queue synchronizer, is an abstract class. We take it apart to see: abstract, queue, synchronizer, I will not explain here, and so I read the series of articles on AQS know why you want to take this name. We read the source code is an important step is to read the source code comments, so I'll comment AQS roughly translates summarized as follows:

 

AQS is a synchronization framework provided by the developer, which has helped us to achieve the CLH queue, the thread into a series of complex logic team team, and wake-up thread blocks, we only need to achieve the appropriate method according to their needs

  • tryAcquire: acquiring exclusive mode synchronization state

  • tryRelease: exclusive mode synchronization state release

  • tryAcquireShared: acquiring synchronization status shared mode

  • tryReleaseShared: release synchronization state shared mode

  • isHeldExclusively: exclusive mode, to see whether the current thread acquire synchronization status 

 

AQS offers two modes: exclusive mode and shared mode

 

Exclusive mode means that only one thread can get the lock and execute the relevant code, while at the same time sharing mode means you can have multiple threads to get the lock to work together. If you need to use an exclusive mode subclass, 1,2 replication method is just above; If you want to use a shared mode, the method only requires 3,4 replication; fifth method is generally used in the AQS ConditionObject (which is the only condition variable) rewrite

 

AQS is actually a classic template pattern of cases, five of the above methods is the template method. concurrent package ReentrantLock, CountDownLatch, Semaphor are all AQS this "template" made out of, so we have the AQS, basically concurrent package under other types of source can be quickly grasped, here we take a look at the specific AQS it

 

II. What are the three tricks

 

Our analysis of AQS, first proposed to focus on three points, three points is the cornerstone of AQS, is the cornerstone of Concurrent package, we can call these three points three tricks Java concurrent programming:

  1. Status: our core, AQS AQS and its subclasses and its subclasses all operations are carried out according to the state into. State usually provided volatile, having to ensure visibility, there has to some extent on the ordering

  2. CAS: CAS tools Unsafe operation is achieved, which has atomic operation, we generally like to change state by the CAS. (Volatile state is modified, it has visibility and orderly, it changes state when CAS is thread-safe)

  3. Queue: waiting for the operation to save resources, generally linked list data structure. When requesting thread not met in a short time, a thread will be packed into a certain type of data structure in a queue, when the condition that a queue will be to re-acquire lock out 

Here we are introduced one by one AQS there are three tricks

 

The first three tricks: state

 

The first ax: status:

/**
* The synchronization state.
*/
private volatile int state;

In the AQS synchronization state is also called, it is a modified volatile int type attribute, when operated CAS is thread-safe. If it is exclusive mode, indicating at the same time only one thread can execute to get the lock, so the state only 0 and 1, is 0 instructions at this time there is a thread already holds the lock, but the lock still is a description at this time you can get a lock to perform. If it is a shared mode, the state can get the maximum value for the number of locks at the same time thread. When we explain the fact AQS does not relate to the operation of the synchronous state, because this state synchronization operations are generally carried out in the template method we implemented in sub-class, so I'll explain this in ReentrantLock and in Semaphore

 

The synchronization status is associated with the lock state, we have to determine whether there is a lock according to this state. And related to our state of the thread, within the class Node AQS in, and we three tricks in the queue is composed of Node, so we put the state on the thread queue explain

 

 

Four Second tricks: CAS

 

Let's paste the code in the CAS AQS

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;

static {
   try {
       stateOffset = unsafe.objectFieldOffset
           (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
       headOffset = unsafe.objectFieldOffset
           (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
       tailOffset = unsafe.objectFieldOffset
           (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
       waitStatusOffset = unsafe.objectFieldOffset
           (Node.class.getDeclaredField("waitStatus"));
       nextOffset = unsafe.objectFieldOffset
           (Node.class.getDeclaredField("next"));

   } catch (Exception ex) { throw new Error(ex); }
}


private final boolean compareAndSetHead(Node update) {
   return unsafe.compareAndSwapObject(this, headOffset, null, update);
}


private final boolean compareAndSetTail(Node expect, Node update) {
   return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}


private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) {
   return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update);
}

private static final boolean compareAndSetNext(Node node, Node expect, Node update) {
   return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}

First, you can see there are five long type of property, the five attributes representing the offset state, head, tail, waitStatus, next is (as we address on the line), in which the state, head, tail is property of AQS, waitStatus , next to the interior AQS Node class attributes. We will see later, these properties are volatile modified, so you can guess these properties must be multi-threaded racing modified target.

 

Static blocks in these five attributes are initialized offset

 

As for the latter method final four Unsafe class calls inside the CAS method. CAS is called comparative swap operation, we have the following code as an example that under the CAS general execution flow

unsafe.compareAndSwapObject(this, tailOffset, expect, update);

When the CAS, will take on the value of the address tailOffset and expect to do the comparison, if the same, it will be the value of the address is updated to update, and returns true, otherwise direct returns false. About CAS described in more detail, we can look for relevant information online look

 

V. 3 tricks: Queue

 

AQS divided into two in the queue, called queue, there is still a condition queue, wait queue is a bidirectional linked list structure, the condition is a singly linked list queues, which are by AQS inner class Node to be described below to achieve the following is the code Node


static final class Node {
    
   static final Node SHARED = new Node();

   static final Node EXCLUSIVE = null;

   static final int CANCELLED =  1;

   static final int SIGNAL    = -1;

   static final int CONDITION = -2;

   static final int PROPAGATE = -3;

   volatile int waitStatus;

   volatile Node prev;

   volatile Node next;

   volatile Thread thread;

   Node nextWaiter;

   final boolean isShared() {
       return nextWaiter == SHARED;
   }

   final Node predecessor() throws NullPointerException {
       Node p = prev;
       if (p == null)
           throw new NullPointerException();
       else
           return p;
   }

   Node() {    // Used to establish initial head or SHARED marker
   }


   Node(Thread thread, Node mode) {     // Used by addWaiter
       this.nextWaiter = mode;
       this.thread = thread;
   }

   Node(Thread thread, int waitStatus) { // Used by Condition
       this.waitStatus = waitStatus;
       this.thread = thread;
   }
}

This structure is actually a typical two-way linked list structure (queue), since it can do a doubly linked list, and certainly can do a one-way linked list (condition queue). It can be used to save the waiting thread and thread status information.

 

We first introduce volatile modified properties, modified volatile properties are generally operated by CAS, also shows that these attributes need to ensure the security thread in a concurrent case

  1. prev: doubly linked list predecessor node

  2. next: the successor node of a doubly linked list

  3. Thread node represents: thread

  4. waitStatus: state of the node in which the thread, i.e., a state of waiting for the lock

 

Then look at four static modification of the properties below

  1. CANCELLED: thread in this node was canceled

  2. SIGNAL: Thread successor node of this node is suspended, needs to be awakened

  3. CONDITION: Thread the node is waiting for a signal, but also indicates that the current node is not in sync queue, the queue in condition

  4. PROPAGATE: a next node should unconditional propagation acquireShared

 

This property is particularly four state waitStatus property, there is an implicit specific state, i.e. waitStatus initialized to zero. In exclusive mode, we only need to use CANCELLED and SIGNAL, to note here is SIGNAL, which represents the state of the thread is not their own, but its successor node status, when waitStatus a node is set to SIGNAL, show successor of this node is suspended, the lock is released when the node or canceled when to give up to get a lock, you should wake successor node. While in shared mode, we will use CANCELLED and PROPAGATE

 

Finally, look at the three properties of type Node

  1. nextWaiter: Node which this mode is labeled; if null, a exclusive mode, compared to empty Node sharing mode

  2. SHARED: nextWaiter specific state, representing the sharing mode

  3. EXCLUSIVE: nextWaiter a particular state, representing Exclusive

 

Well AQS first article of concurrent three tricks to finish it, and there are four, these days will continue to organize impress. Tomorrow is the Ching Ming Festival, the epidemic is not over, we still stay at home and rest for the state contribution to doing it.

 

(Unfinished)

I welcome everyone's attention the public number "Advanced programmers Road", which records the way a non-programmer Coban Growth

                                                 

Published 114 original articles · won praise 199 · Views 200,000 +

Guess you like

Origin blog.csdn.net/qq_36582604/article/details/105303748