天天看點

4.JUC之AQS架構一、簡介二、作用三、原理四、用法

一、簡介

1.AQS

AQS是AbstractQueuedSynchronizer的簡寫,直白的翻譯:抽象隊列同步器,jdk1.5後出現

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic 

int

value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being 

acquired

 or

released

. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization. ——Java docs

翻開源碼,首先是一大段的注釋,然後可以看開AQS繼承自AbstractOwnableSynchronizer。當你翻開AbstractOwnableSynchronizer時,還是先看到小段的說注釋。

A synchronizer that may be exclusively owned by a thread. This class provides a basis for creating locks and related synchronizers that may entail a notion of ownership. The AbstractOwnableSynchronizer class itself does not manage or use this information. However, subclasses and tools may use appropriately maintained values to help control and monitor access and provide diagnostics. ——Java docs

2.AOS

  生自java1.6,可以由線程以獨占的方式擁有的同步器。此類為建立鎖和相關同步器(伴随着所有權的概念)提供了基礎。

  AbstractOwnableSynchronizer類本身不管理或使用此資訊。但是,子類和工具可以使用适當維護的值幫助控制和監視通路以及提供診斷

  簡而言之,AOS輸出的是一種概念,是一種建立獨占鎖同步器所有權的概念。他自身并沒有規範所有權的管理方式,更沒有用到這些資訊(所有權的資訊)。不過呢,可以幫其子類維護所有者資訊。

  可能上面的話仍然不夠清晰,下面看看源碼。

  AOS提供兩個方法一個字段,外帶一個空構造方法(可無視)

1 /**
 2  * The current owner of exclusive mode synchronization.
 3  */
 4 private transient Thread exclusiveOwnerThread; // transient表示該字段不需要序列化,因為AOS實作了Serializable
 5 
 6 protected final void setExclusiveOwnerThread(Thread thread) {
 7     exclusiveOwnerThread = thread;
 8 }
 9 
10 protected final Thread getExclusiveOwnerThread() {
11     return exclusiveOwnerThread;
12 }      

  這下明白了吧,就是AOS隻維護一個東西------目前誰持有獨占式同步器。是以咱們可以當他不存在,繼續回到AQS

二、作用

  從Java Docs的注釋可以知道,AQS是一個架構,一個提供鎖或同步器依賴于FIFO等待隊列所必要的 “基礎設施”的架構,Doug  Lea之是以寫個抽象類的目的是為了簡化我們實作同步器的工作

也就是說:

  提供一個基于FIFO等待隊列,可以用于建構鎖或其他同步裝置的基礎架構。意在能夠實作大部分同步需求的基礎。

  AQS預設提供了獨占式和共享式兩種模式,JDK對應的實作有ReentrantLock 和 ReentrantReadWriteLock。即除了提供acquire方法之外,還提供了acquireShare。帶shared都是共享模式相關操作,預設則是獨占模式。

  AQS到底提供了哪些便利呢:

  1.管理狀态

  2.實作了線程按安全的CLH隊列

  3.實作了同步器公共方法

  4.ConditionObject

三、原理

  AQS自身就是一個Wait Queue,CLH lock  queue的變種,CLH隊列通常用于自旋鎖。

  The wait queue is a variant of a “CLH” (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks. We instead use them for blocking synchronizers, but use the same basic tactic of holding some of the control information about a thread in the predecessor of its node.

  我們知道Queue的底層實作是一個連結清單結構,我們也知道它可以是單連結清單,也可以是雙連結清單。AQS實作的是一個雙連結清單結構。即每個節點都存儲了前驅和後繼兩個指針,而且Head節點是dummy節點。入隊則tail前驅一個節點,再把新節點接入,然後接入tail節點。

  AQS完全通過CAS解決多線程安全問題,即通過Unsafe完成的。具體可以自行閱讀AQS源碼,在最後幾個方法,非常簡單

  CAS:compareAndSet,Unsafe的CAS方法的語義是先與期望值進行比較,若不相等傳回false;若相等的話,則會把原值修改為新值,再傳回true。這個跟 java.util.concurrent.atomic的原子類的CAS方法是一樣的

  AQS的實作依賴LockSupport完成阻塞和喚醒,也正是LockSupport的引入使用AQS源碼閱讀起來邏輯上有點跳躍。

  什麼是自旋鎖,如下執行個體實作的即是自旋鎖,即是循環等待資訊量變成期望值後完成相關操作

1 // 來自 AQS#doAcquireInterruptibly
 2 private void doAcquireInterruptibly(int arg) throws InterruptedException {
 3     final Node node = addWaiter(Node.EXCLUSIVE);
 4     boolean failed = true;
 5     try {
 6         for (;;) { // 自旋鎖
 7             final Node p = node.predecessor();
 8             if (p == head && tryAcquire(arg)) { // 相當于阻塞到信号量變成期望值
 9                 setHead(node);
10                 p.next = null; // help GC
11                 failed = false;
12                 return;
13             }
14             if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
15                 throw new InterruptedException();
16         }
17     } finally {
18         if (failed)
19             cancelAcquire(node);
20     }
21 }      

注:CAS算法本身不會自旋,但是可以自旋CAS來不停地發送請求,如java.util.concurrent.atomic包,這個包裡面提供了一組原子類

  我們來看一段AtomicBoolean中的自旋鎖的代碼

public final boolean getAndSet(boolean newValue) {
   for (;;) {
       boolean current = get();
       if (compareAndSet(current, newValue))
           return current;
   }
}      

四、用法

  AQS的用法,可以直接參考AQS的注釋,另外也可以參考ReentrantLock的寫法

  private final Sync sync;

  abstract static class Sync extends AbstractQueuedSynchronizer {

  注釋指明了,繼承AQS需要實作下面五個方法,

  tryAcquire(int arg)

  tryRelease(int arg)

  tryAcquireShared(int arg)

  tryReleaseShared(int arg)

  isHeldExclusively()

  它們帶的int參數,用來表示狀态,如下面的示例中,用了1和0表示鎖和釋放

  如你所知,前兩個是獨占式,中間兩個是共享式。最後一個是測試同步器是否正被持有獨占鎖。即是已有線程持有這個排它鎖,且還未釋放

  

  後面一篇部落格分析這些方法在什麼情況下被調用,是怎麼和我們的程式聯系在一起的

1 class Mutex implements Lock, java.io.Serializable {
 2 
 3     // Our internal helper class
 4     private static class Sync extends AbstractQueuedSynchronizer {
 5         // Report whether in locked state
 6         protected boolean isHeldExclusively() {
 7             return getState() == 1;
 8         }
 9 
10         // Acquire the lock if state is zero
11         public boolean tryAcquire(int acquires) {
12             assert acquires == 1; // Otherwise unused
13             if (compareAndSetState(0, 1)) {
14                 setExclusiveOwnerThread(Thread.currentThread());
15                 return true;
16             }
17             return false;
18         }
19 
20         // Release the lock by setting state to zero
21         protected boolean tryRelease(int releases) {
22             assert releases == 1; // Otherwise unused
23             if (getState() == 0)
24                 throw new IllegalMonitorStateException();
25             setExclusiveOwnerThread(null);
26             setState(0);
27             return true;
28         }
29 
30         // Provide a Condition
31         Condition newCondition() {
32             return new ConditionObject();
33         }
34 
35         // Deserialize properly
36         private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
37             s.defaultReadObject();
38             setState(0); // reset to unlocked state
39         }
40     }
41 
42     // The sync object does all the hard work. We just forward to it.
43     private final Sync sync = new Sync();
44 
45     public void lock() {
46         sync.acquire(1);
47     }
48 
49     public boolean tryLock() {
50         return sync.tryAcquire(1);
51     }
52 
53     public void unlock() {
54         sync.release(1);
55     }
56 
57     public Condition newCondition() {
58         return sync.newCondition();
59     }
60 
61     public boolean isLocked() {
62         return sync.isHeldExclusively();
63     }
64 
65     public boolean hasQueuedThreads() {
66         return sync.hasQueuedThreads();
67     }
68 
69     public void lockInterruptibly() throws InterruptedException {
70         sync.acquireInterruptibly(1);
71     }
72 
73     public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
74         return sync.tryAcquireNanos(1, unit.toNanos(timeout));
75     }
76 }      

原文連結:http://blog.csdn.net/zteny/article/details/54919765

轉載于:https://www.cnblogs.com/xuzekun/p/7483978.html

上一篇: 公平不公平
下一篇: 不公平