<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # AQS 隊列同步器AbstractQueuedSynchronizer,用來構建鎖或者其他同步組件的基礎框架,內部使用一個變量state來表示同步狀態,同時使用一個FIFO隊列來完成線程的排隊工作。 鎖或者其他同步組件一般都會定義一個靜態內部類,該靜態內部類會繼承AQS,同時**重寫**AQS中的方法,重寫AQS中的方法時需要用到下面三個方法來獲取同步狀態。 - **getState()** 獲取state屬性的內容。 - **setState(int newState)** 設置state屬性的內容。 - **compareAndSetState(int expect, int update)** 使用CAS設置當前狀態,保證狀態設置的原子性。 > 總結:如何自定義一個鎖或者同步組件? > 創建靜態內部類繼承AQS,重寫AQS中的**可重寫**的方法,在里面使用AQS提供的如上三個方法來獲取、修改同步狀態。最后調用AQS中的模板方法來進行操作,模板方法中會調用重寫的方法。 > **即使用者調用模板方法,模板方法調用重寫方法,重寫方法調用如上三個方法。** :-: ![](https://img.kancloud.cn/ec/d8/ecd87535e99d81e7fc1de29eb7bf6e84_1092x589.png) &nbsp; ## 可重寫的方法 1. ``` protected boolean tryAcquire(int arg); ``` **獨占式獲取**同步狀態,查詢當前狀態并根據具體條件設置同步狀態。 2. ``` protected boolean tryRelease(int arg); ``` **獨占式釋放**同步狀態,等待的線程有機會獲取同步狀態。 3. ``` protected int tryAcquireShared(int arg); ``` **共享式獲取**同步狀態,返回大于等于0的值表示獲取成功,反之獲取失敗。 4. ``` protected boolean tryReleaseShared(int arg); ``` **共享式釋放**同步狀態。 5. ``` protected boolean isHeldExclusively(); ``` 表示是否被當前線程占用。 &nbsp; ## 模板方法 1. 獨占式獲取同步狀態 ``` void acquire(int arg); ``` 當前線程獲取成功則會返回,否則進入同步隊列**等待**,調用重寫方法中的**tryAcquire**。 2. 獨占式獲取同步狀態,響應中斷 ``` void acquireInterruptible(int arg); ``` 如果當前線程被中斷,則會拋出InterruptedException。 3. 超時獲取同步狀態 ``` boolean tryAcquireNanos(int arg, long nanos); ``` 在acquireInterruptible的基礎上設置超時時間,如果超時時間還沒有獲取到同步狀態,會返回false,否則返回true。 4. 共享獲取同步狀態 ``` void acquireShared(int arg); ``` 5. 共享獲取同步狀態,響應中斷 ``` void acquireSharedInterruptible(int arg); ``` 6. 共享獲取同步狀態,響應中斷,添加超時時間 ``` boolean tryAcquireSharedNanos(int arg, long nanos); ``` 7. 獨占式釋放同步狀態 ``` boolean release(int arg); ``` 同步隊列中的第一個節點將會被喚醒。 8. 共享式釋放同步狀態 ``` boolean releaseShared(int arg); ``` 9. 獲取等待在同步隊列上的線程集合 ``` Collection<Thread> getQueuedThreads(); ``` 總之:模板可以分為三類:獨占式獲取與釋放同步狀態、共享式獲取與釋放同步狀態、查詢同步隊列線程等待情況。獲取又有分為`中斷`、`超時`。 &nbsp; ## 自定義同步組件 ~~~ /** * 自定義不可重入鎖 */ public class UnReetrantLock implements Lock { // 同步鎖 public static class Sync extends AbstractQueuedSynchronizer { /** * 嘗試獨占式獲取鎖 * * @param arg * @return */ @Override protected boolean tryAcquire(int arg) { if (compareAndSetState(0, 1)) { // 調用CAS,當state為0時獲取成功,底層由C++提供 // 加上鎖了 // 設置持有鎖的線程 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } /** * 嘗試釋放鎖 * * @param arg * @return */ @Override protected boolean tryRelease(int arg) { // 不會有其他線程競爭、直接設置就行了 setExclusiveOwnerThread(null); setState(0); // 保證前面的內容對其他線程可見 return false; } @Override protected boolean isHeldExclusively() { return getState() == 1; } public Condition newCondition() { return new ConditionObject(); } } private Sync sync = new Sync(); @Override public void lock() { sync.acquire(1); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(time)); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } } ~~~ &nbsp; ## AQS實現 **底層數據結構:同步隊列** AQS中使用一個雙向鏈表來保存等待同步狀態的線程,鏈表的節點用其內部自定義的Node表示,Node類源碼: ~~~ static final class Node { static final Node SHARED = new Node(); static final Node EXCLUSIVE = null; // 同步狀態 volatile int waitStatus; volatile Node prev; volatile Node next; // 線程引用 volatile Thread thread; Node nextWaiter; } ~~~ waitStatus有五個狀態: - cancelled = 1:同步隊列中的線程等待超時或者中斷時的狀態,后續不會再改變。 - signal = -1:節點獲取同步狀態,一般是隊頭節點,后續節點處于等待狀態。 - condition = -2:節點在等待隊列中(注意不是同步隊列),線程等待Condition,當Condition調用了signal()之后,該節點會從**等待隊列**轉移到**同步隊列**。 - propagate = -3: - initial = 0:初始狀態。 同步隊列采用尾插法的方式,同時會使用CAS保證尾插的時候是線程安全的。其結構如下: :-: ![](https://img.kancloud.cn/88/ff/88ff8ad5fad5ceddd726eac9d92662b6_892x350.png) 其中隊頭是獲取同步狀態成功的節點,當首節點的線程釋放同步狀態的時候,會喚醒后繼的節點,后繼節點會成為首節點。(這個過程不用CAS,沒有競爭的情況。) **acquire方法流程** ~~~ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } ~~~ :-: ![](https://img.kancloud.cn/86/0e/860eee5226ec9a94eedf5c3a9d220312_887x722.png) 同步隊列中的節點不斷的在自旋判斷其**前驅節點是不是頭節點**,如果是則嘗試獲取同步狀態,否則會阻塞節點中的線程。 **acquireShared方法流程** ~~~ public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); } ~~~ :-: ![](https://img.kancloud.cn/4d/d8/4dd803aff2d53d8b8b27f923533ba95e_925x699.png) ## ReetantLock ReentrantLock,支持重入鎖和公平與非公平鎖。 &nbsp; ### ReentrantLock實現可重入 重入鎖:支持線程反復的獲取鎖資源而不會自己阻塞自己,有兩個問題要實現: 1. 線程再次獲取鎖,判斷是否是當前線程獲取鎖。 2. 鎖的最終釋放,需要計數鎖被重入幾次,計數器最終釋放為0時才表示鎖的最終釋放。 :-: ![](https://img.kancloud.cn/f0/c6/f0c68a8e0dde268ff6346d568ba131bf_932x506.png) 例如非公平鎖每次再嘗試獲取鎖的時候都會判斷是不是同個線程,如果是的話增加計數器的值。釋放鎖時等到計數器的值為0時才將占有鎖的線程設置為null。 :-: ![](https://img.kancloud.cn/ff/fd/fffd95b0ff268f37137bdb4768104bc2_920x363.png) &nbsp; ### 公平鎖與非公平鎖 公平鎖:獲取鎖的線程按照絕對的時間順序,FIFO。 非公平鎖:只要CAS設置同步狀態成功,就獲取鎖,不會按照FIFO順序。 ReentrantLock的構造方法中傳入true時可以創建公平鎖: ~~~ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } ~~~ 公平鎖在tryAcquire的時候會判斷當前線程是否有前驅節點,有的話則會等待前驅節點釋放之后在獲取嘗試獲取鎖。 公平鎖的tryAcquire: :-: ![](https://img.kancloud.cn/24/e2/24e231a5f7ab6f03340aa1a89c823e8d_978x611.png) hasQueuePredecessors方法用來判斷是否有前驅節點 非公平鎖的tryAcquire: :-: ![](https://img.kancloud.cn/20/ce/20ced0fe4146742378f9716402b714a7_868x514.png) > 問:如何實現公平鎖? > 構造函數的參數傳入true,在重寫的tryAcquire方法中判斷當前線程是否有前驅線程,有的話嘗試獲取同步狀態失敗,以此來達到公平的效果。 對比: 公平鎖雖然會按照FIFO原則,但是會進行大量的線程切換,非公平鎖雖然可能會造成其他線程饑餓,但是可以極大提高吞吐量。 &nbsp; :-: ![](https://img.kancloud.cn/a2/a4/a2a482a54328499aab8f34ae642e3f8f_1452x306.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看