使用遞增計數器的線程同步工具 —— 信號量,它的原理是什麼樣子的?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 JUC 中線程同步器除了 CountDownLatch 和 CycleBarrier ,還有一個叫做 Semaphore (信號量),同樣是基於 AQS 實現的。下面來看看信號量的內部原理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"公衆號:liuzhihangs,記錄工作學習中的技術、開發及源碼筆記;時不時分享一些生活中的見聞感悟。歡迎大佬來指導!"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"介紹"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個計數信號量。 從概念上講,信號量維護了一組許可。 如果有必要,在許可可用之前調用 acquire 方法會被阻塞,直到許可證可用。 調用 release 方法會增加了一個許可證,從而釋放被阻塞的線程。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"聲明時指定初始許可數量。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"調用 acquire(int permits) 方法,指定目標許可數量。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"調用 release(int permits) 方法,發佈指定的許可數量。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在許可數量沒有到達指定目標數量時,調用 acquire 方法的線程會被阻塞。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"基本使用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class SemaphoreTest1 {\n\n private static final Semaphore SEMAPHORE = new Semaphore(0);\n\n public static void main(String[] args) throws InterruptedException {\n\n ExecutorService pool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,\n new LinkedBlockingQueue<>(1024),\n new ThreadFactoryBuilder().setNameFormat(\"Thread-pool-%d\").build(),\n new ThreadPoolExecutor.AbortPolicy());\n\n\n for (int i = 0; i < 5; i++) {\n\n pool.submit(() -> {\n\n try {\n Thread.sleep(1000 + new Random().nextInt(1000));\n } catch (InterruptedException ignored) {\n }\n\n System.out.println(\"當前線程: \" + Thread.currentThread().getName() + \" 發佈一個許可\");\n SEMAPHORE.release(1);\n\n });\n }\n\n System.out.println(\"-----> 這裏是主線程\");\n\n SEMAPHORE.acquire(5);\n\n System.out.println(\"-----> 主線程執行完畢\");\n\n pool.shutdown();\n }\n\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"-----> 這裏是主線程\n當前線程: Thread-pool-2 發佈一個許可\n當前線程: Thread-pool-4 發佈一個許可\n當前線程: Thread-pool-1 發佈一個許可\n當前線程: Thread-pool-0 發佈一個許可\n當前線程: Thread-pool-3 發佈一個許可\n-----> 主線程執行完畢"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面這個方法也是模擬了類似 CountDownLatch 的用法, 在子線程執行完畢之後,主線程繼續執行。只不過 Semaphore 和 CountDownLatch 區別最大的是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Semaphore 是從指定數值開始增加,直到到達許可數量,然後被阻塞線程開始繼續執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CountDownLatch 是從指定數量的線程開始減少,直到爲 0 時,被阻塞的線程開始繼續執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然這只是最簡單的用法,除此讓主線程等待,同樣也可以讓其他線程等待,然後再開始執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"問題疑問"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"Semaphore 和 AQS 有什麼關係?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"Semaphore 和 CountDownLatch 有什麼區別?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"源碼分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"基本結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f4faaa831bd71d626b257aaf6b06300.png","alt":"Semaphore-cover-iGaTzJ","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過類圖可以看出在 Semaphore 裏面有一個靜態內部類 Sync 繼承了 AQS,同時爲了區分公平和非公平的情況,Sync 分別有兩個子類:NonfairSync 、FairSync。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面根據案例分別從構造函數、acquire()、release() 入手,從而瞭解內部實現原理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"初始化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Semaphore(int permits) {\n sync = new NonfairSync(permits);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"初始化默認非公平鎖, 同時需要傳入指定許可數, 可以看到這塊代碼是調用的 AQS 的 setState(permits) 方法。代碼如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"static final class NonfairSync extends Sync {\n private static final long serialVersionUID = -2694183684443567898L;\n\n NonfairSync(int permits) {\n super(permits);\n }\n}\n\nabstract static class Sync extends AbstractQueuedSynchronizer {\n private static final long serialVersionUID = 1192457210091910933L;\n\n Sync(int permits) {\n setState(permits);\n }\n }\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"setState 方法其實就是對 AQS 的 state 進行賦值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"補充"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 在 ReentrantLock 中 state 代表加鎖狀態,0 沒有線程獲得鎖,大於等於 1 已經有線程獲得鎖,大於 1 說明該獲得鎖的線程多次重入。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 在 ReentrantReadWriteLock 中 state 代表鎖的狀態。state 爲 0 ,沒有線程持有鎖,state 的高 16 爲代表讀鎖狀態,低 16 爲代表寫鎖狀態。通過位運算可以獲取讀寫鎖的實際值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 而在這裏 (CountDownLatch)則代表門閂或者說計數的值。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果對 state 有所遺忘,可以閱讀前面的 AQS 、CAS 相關代碼。 state 在這裏代表的是信號量的許可數量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"acquire()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void acquire() throws InterruptedException {\n sync.acquireSharedInterruptibly(1);\n}\n\npublic void acquire(int permits) throws InterruptedException {\n if (permits < 0) throw new IllegalArgumentException();\n sync.acquireSharedInterruptibly(permits);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"acquire() 和 acquire(int permits) 調用的都是 sync.acquireSharedInterruptibly(permits) 方法,只不過一個支持傳遞參數,一個默認爲 1。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"acquireSharedInterruptibly 方法,其實就是 Sync 繼承自 AQS 的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這塊可以閱讀 AQS 的文章,這裏簡單介紹下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void doAcquireSharedInterruptibly(int arg)\n throws InterruptedException {\n final Node node = addWaiter(Node.SHARED);\n boolean failed = true;\n try {\n for (;;) {\n final Node p = node.predecessor();\n if (p == head) {\n int r = tryAcquireShared(arg);\n if (r >= 0) {\n setHeadAndPropagate(node, r);\n p.next = null; // help GC\n failed = false;\n return;\n }\n }\n if (shouldParkAfterFailedAcquire(p, node) &&\n parkAndCheckInterrupt())\n throw new InterruptedException();\n }\n } finally {\n if (failed)\n cancelAcquire(node);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"在失敗後會使用 "},{"type":"codeinline","content":[{"type":"text","text":"doAcquireSharedInterruptibly(arg);"}]},{"type":"text","text":" 不斷獲取資源;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"final Node node = addWaiter(Node.SHARED);"}]},{"type":"text","text":" 會創建節點以共享模式放到隊列裏;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"在循環中不斷判斷前一個節點,如果是 head,則嘗試獲取共享資源;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"在共享模式下獲取到資源後會使用 "},{"type":"codeinline","content":[{"type":"text","text":"setHeadAndPropagate(node, r);"}]},{"type":"text","text":" 設置頭節點,同時喚醒後續節點。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"tryAcquireShared 是需要子類實現,也就是在 Semaphore.Sync 的實現類中實現了,這裏以 FairSync 做講解:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\nstatic final class FairSync extends Sync {\n private static final long serialVersionUID = 2014338818796000944L;\n\n FairSync(int permits) {\n super(permits);\n }\n\n protected int tryAcquireShared(int acquires) {\n for (;;) {\n // 如果前面有節點,則直接返回 -1 表示失敗\n if (hasQueuedPredecessors())\n return -1;\n // 獲取當前信號量\n int available = getState();\n // 獲取當前剩餘量\n int remaining = available - acquires;\n // 如果小於 0 或者 CAS 設置信號量成功 則直接返回\n if (remaining < 0 ||\n compareAndSetState(available, remaining))\n return remaining;\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而這段代碼的含義:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"如果前面有節點,則直接阻塞;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"如果當前剩餘信號量小於 0 ,則返回負值,直接阻塞;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"如果當前剩餘量大於等於 0 ,會 CAS 更新信號量,並返回非負數。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">這塊數值的含義,在 AQS 中定義了,含義如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">1. 小於 0: 表示失敗;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">2. 等於 0: 表示共享模式獲取資源成功,但後續的節點不能以共享模式獲取成功; "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">3. 大於 0: 表示共享模式獲取資源成功,後續節點在共享模式獲取也可能會成功,在這種情況下,後續等待線程必須檢查可用性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"release()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void release() {\n sync.releaseShared(1);\n}\npublic void release(int permits) {\n if (permits < 0) throw new IllegalArgumentException();\n sync.releaseShared(permits);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"發佈許可證的給定數量,該數量增加可用的許可數量。 看其內部調用的是 Sync 的 releaseShared, 其實就是 AQS 的對應方法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\npublic final boolean releaseShared(int arg) {\n if (tryReleaseShared(arg)) {\n doReleaseShared();\n return true;\n }\n return false;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果實現tryReleaseShared返回true,以共享模式釋放資源。 其中的 tryReleaseShared 部分由 Semaphore.Sync 中實現,邏輯如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\nprotected final boolean tryReleaseShared(int releases) {\n for (;;) {\n // 獲取當前 state\n int current = getState();\n // 對 state 進行增加\n int next = current + releases;\n if (next < current) // overflow\n throw new Error(\"Maximum permit count exceeded\");\n // 使用 CAS 賦值\n if (compareAndSetState(current, next))\n return true;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過上面代碼可以看出,在 Semaphore 的 release 方法中主要就是對 state 進行增加,增加成功後會調用 AQS 的 doReleaseShared 方法喚醒頭節點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Q&A"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Q: 既然 Semaphore 也是基於 AQS, 那在 Semaphore 中 state 的含義代表什麼?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"A:"},{"type":"text","text":" 在 Semaphore 中 state 代表許可數量,acquire 方法當許可小於指定數量會阻塞線程,release 方法增加許可當許可增加成功則喚醒阻塞節點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Q: Semaphore 基於 AQS 具體是怎麼實現的呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"A:"},{"type":"text","text":" "}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"初始設置 state 的初始值,即初始許可數量。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"acquire 方法設置目標數量,當目標數量大於當前數量時,會阻塞線程並將其放到阻塞隊列中。此處基於 AQS 實現。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"release 對 state 進行增加,成功後會調用 AQS 的 doReleaseShared 喚醒頭結點。同樣是基於 AQS 實現。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Q: Semaphore 和 CountDownLatch 有什麼區別?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"A:"},{"type":"text","text":" Semaphore 的計數器是遞加的,而 CountDownLatch 是遞減的。相同點就是計數器都不可以重置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"結束語"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在閱讀 Semaphore 源碼過程中,發現其主要功能都是基於 AQS 實現的,可以回顧閱讀 AQS 的相關筆記。同樣 Semaphore 也支持公平和非公平模式,這塊就需要小夥伴自己去閱讀啦。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章