核酸檢測:讓我明白AQS原理

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"春節越來越近了,疫情也越來越嚴重但擋不住叫練攜一家老小回老家(湖北)團聚的衝動。響應國家要求,我們去做","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"核酸檢測","attrs":{}},{"type":"text","text":"了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/40/40176aa84c0adbe2047b33d1d7916436.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"獨佔鎖","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"早上叫練帶着一家三口來到了南京市第一醫院做核酸檢測,護士小姐姐站在醫院門口攔着告訴我們人比較多,無論大人小孩,需要排隊一個個等待醫生採集唾液檢測,OK,下面我們用代碼+圖看看我們一家三口是怎麼排隊的!","attrs":{}}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"import java.util.concurrent.locks.ReentrantReadWriteLock;\n\n/**\n * @author :jiaolian\n * @date :Created in 2021-01-22 10:33\n * @description:獨佔鎖測試\n * @modified By:\n * 公衆號:叫練\n */\npublic class ExclusiveLockTest {\n\n private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();\n\n private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();\n\n //醫院\n private static class Hospital {\n\n private String name;\n\n public Hospital(String name) {\n this.name = name;\n }\n\n //核酸檢測排隊測試\n public void checkUp() {\n try {\n writeLock.lock();\n System.out.println(Thread.currentThread().getName()+\"正在做核酸檢測\");\n //核酸過程...難受...\n Thread.sleep(3000);\n } catch (InterruptedException e) {\n e.printStackTrace();\n } finally {\n writeLock.unlock();\n }\n }\n }\n\n\n public static void main(String[] args) throws InterruptedException {\n Hospital hospital = new Hospital(\"南京市第一醫院\");\n Thread JLWife = new Thread(()->hospital.checkUp(),\"叫練妻\");\n JLWife.start();\n //睡眠100毫秒是讓一家三口是有順序的排隊去檢測\n Thread.sleep(100);\n Thread JLSon = new Thread(()->hospital.checkUp(),\"叫練子\");\n JLSon.start();\n Thread.sleep(100);\n Thread JL = new Thread(()->hospital.checkUp(),\"叫練\");\n JL.start();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上代碼:在主線程啓動三個線程去醫院門口排隊,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"女士優先","attrs":{}},{"type":"text","text":",叫練妻是排在最前面的,中間站的是叫練的孩子,最後就是叫練自己了。我們假設模擬了下核酸檢測一次需要3秒。代碼中我們用了獨佔鎖,獨佔鎖可以理解成醫院只有一個醫生,一個醫生同時只能爲一個人做核酸,所以需要逐個排隊檢測,所以代碼執行完畢一共需要花費9秒,核酸檢測就可以全部做完。代碼邏輯還是比較簡單,和我們之前文章描述synchronized同理。核酸排隊我們用圖描述下吧!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/26/26d3da2be582e918686a2bfe681c595e.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"AQS全稱是","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"AbstractQueueSynchroniz,意爲隊列同步器","attrs":{}},{"type":"text","text":",本質上是一個雙向鏈表,在AQS裏面每個線程都被封裝成一個Node節點,每個節點都通過尾插法添加。另外節點還有還封裝狀態信息,比如是獨佔的還是共享的,如上面的案例就表示獨佔Node,醫生他本身是一種共享資源,在AQS內部裏面叫它state,用int類型表示,線程都會通過CAS的方式爭搶state。線程搶到鎖了,就自增,沒有搶到鎖的線程會阻塞等待時機被喚醒。如下圖:根據我們理解抽象出來AQS的內部結構。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8b/8bc8be5a27aba3e0b378b6465becdb9a.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"根據上面描述,大家看AQS不就是用Node封裝線程,然後把線程按照先來後到(","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"非公平鎖除外","attrs":{}}]},{"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"共享鎖","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面我們做核酸的過程是同步執行的,叫獨佔鎖。那共享鎖是什麼意思呢?現在叫練孩子只有3歲,不能獨立完成核酸檢測,護士小姐姐感同身受,觀察叫練子是排在叫練妻後面的,就讓他們一起同時做核酸檢測。這種同時做核酸的操作,相當於同時去獲取醫生資源,我們稱之爲共享鎖。下面是我們測試代碼。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"import java.util.concurrent.locks.ReentrantReadWriteLock;\n\n/**\n * @author :jiaolian\n * @date :Created in 2021-01-21 19:54\n * @description:共享鎖測試\n * @modified By:\n * 公衆號:叫練\n */\npublic class SharedLockTest {\n\n private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();\n\n private static ReentrantReadWriteLock.ReadLock readLock = lock.readLock();\n\n //醫院\n private static class Hospital {\n\n private String name;\n\n public Hospital(String name) {\n this.name = name;\n }\n\n //核酸檢測排隊測試\n public void checkUp() {\n try {\n readLock.lock();\n System.out.println(Thread.currentThread().getName()+\"正在做核酸檢測\");\n //核酸過程...難受...\n Thread.sleep(3000);\n } catch (InterruptedException e) {\n e.printStackTrace();\n } finally {\n readLock.unlock();\n }\n }\n }\n\n\n public static void main(String[] args) throws InterruptedException {\n Hospital hospital = new Hospital(\"南京市第一醫院\");\n Thread JLWife = new Thread(()->hospital.checkUp(),\"叫練妻\");\n JLWife.start();\n //睡眠100毫秒是讓一家三口是有順序的排隊去檢測\n Thread.sleep(100);\n Thread JLSon = new Thread(()->hospital.checkUp(),\"叫練子\");\n JLSon.start();\n /*Thread.sleep(100);\n Thread JL = new Thread(()->hospital.checkUp(),\"叫練\");\n JL.start();*/\n }\n \n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面代碼我們用ReentrantReadWriteLock.ReadLock作爲讀鎖,在主線程啓動“叫練妻”和“叫練”兩個線程,本來母子倆一共需要6秒才能完成的事情,現在只需要3秒就可以做完,共享鎖好處是效率比較高。如下圖,是AQS內部某一時刻Node節點狀態。對比上圖,","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"Node的狀態變爲了共享狀態,這些節點可以同時去共享醫生資源","attrs":{}},{"type":"text","text":"!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/80a40a319e54f79ebb5ec0d874871b15.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"synchronized鎖不響應中斷","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"/**\n * @author :jiaolian\n * @date :Created in 2020-12-31 18:17\n * @description:sync不響應中斷\n * @modified By:\n * 公衆號:叫練\n */\npublic class SynchronizedInterrputedTest {\n\n private static class MyService {\n\n public synchronized void lockInterrupt() {\n try {\n System.out.println(Thread.currentThread().getName()+\" 獲取到了鎖\");\n while (true) {\n //System.out.println();\n }\n } catch (Exception e) {\n e.printStackTrace();\n }\n }\n }\n\n public static void main(String[] args) throws InterruptedException {\n MyService myService = new MyService();\n //先啓動線程A,讓線程A先擁有鎖\n Thread threadA = new Thread(()->{\n myService.lockInterrupt();\n });\n threadA.start();\n Thread.sleep(1000);\n //啓動線程B,中斷,synchronized不響應中斷!\n Thread threadB = new Thread(()->{\n myService.lockInterrupt();\n });\n threadB.start();\n Thread.sleep(1000);\n threadB.interrupt();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上述代碼:先啓動A線程,讓線程A先擁有鎖,睡眠1秒再啓動線程B是讓B線程處於可運行狀態,隔1秒後再中斷B線程。在控制檯輸出如下:A線程獲取到了鎖,等待2秒後控制檯並沒有立刻輸出報錯信息,程序一直未結束執行,說明","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"synchronized鎖不響應中斷,需要B線程獲取鎖後纔會輸出線程中斷報錯信息!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e6/e6a0ef5de62cdf4c7e1ecbf66ebfa265.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"AQS響應中斷","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經常做比較知識才會融會貫通,在Lock提供lock和lockInterruptibly兩種獲取鎖的方式,其中lock方法和","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"synchronized","attrs":{}},{"type":"text","text":"是不響應中斷的,那下面我們看看","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"lockInterruptibly","attrs":{}},{"type":"text","text":"響應中斷是什麼意思。我們還是用核酸案例說明。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"import java.util.concurrent.locks.ReentrantReadWriteLock;\n\n/**\n * @author :jiaolian\n * @date :Created in 2021-01-22 15:18\n * @description:AQS響應中斷代碼測試\n * @modified By:\n * 公衆號:叫練\n */\npublic class AQSInterrputedTest {\n\n private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();\n\n private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();\n\n //醫院\n private static class Hospital {\n\n private String name;\n\n public Hospital(String name) {\n this.name = name;\n }\n\n //核酸檢測排隊測試\n public void checkUp() {\n try {\n writeLock.lockInterruptibly();\n System.out.println(Thread.currentThread().getName()+\"正在做核酸檢測\");\n //核酸過程...難受...\n Thread.sleep(3000);\n } catch (InterruptedException e) {\n e.printStackTrace();\n } finally {\n writeLock.unlock();\n }\n }\n }\n\n\n public static void main(String[] args) throws InterruptedException {\n Hospital hospital = new Hospital(\"南京市第一醫院\");\n Thread JLWife = new Thread(()->hospital.checkUp(),\"叫練妻\");\n JLWife.start();\n //睡眠100毫秒是讓一家三口是有順序的排隊去檢測\n Thread.sleep(100);\n Thread JLSon = new Thread(()->hospital.checkUp(),\"叫練子\");\n JLSon.start();\n Thread.sleep(100);\n Thread JL = new Thread(()->hospital.checkUp(),\"叫練\");\n JL.start();\n //等待1秒,中斷叫練線程\n System.out.println(\"護士小姐姐想和叫練私聊會!\");\n Thread.sleep(1000);\n JL.interrupt();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上代碼:叫練一家三口採用的是獨佔鎖排隊去做核酸,叫練線程等待一秒後,護士小姐姐想和叫練私聊會!莫非小姐姐會有啥想法,於是叫練立刻中斷了這次的核酸檢測,注意是","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"立刻中斷","attrs":{}},{"type":"text","text":"。控制檯打印結果如下:叫練妻線程和叫練子線程都做了核酸,但叫練卻沒有做成功!因爲被護士小姐姐中斷了,結果如下圖所示。所以我們能得出結論,在aqs中鎖是可以響應中斷的。現在如果將上述代碼中lockInterruptibly方法換成lock方法會發生什麼情況呢,如果換成這種方式,小姐姐再來撩我,叫練要先成功獲取鎖,也就說叫練已經到醫生旁邊準備做核酸了,小姐姐突然說有事找叫練,","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"最終導致叫練沒有做核酸","attrs":{}},{"type":"text","text":",碰上這樣的事,只能說小姐姐是存心的,小姐姐","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"太壞","attrs":{}},{"type":"text","text":"了。關於lock方法不響應中斷的測試大家可以自己測試下。看看我是不是","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"冤枉","attrs":{}},{"type":"text","text":"護士小姐姐了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以得出結論:在aqs中如果一個線程正在獲取鎖或者處於等待狀態,另一個線程中斷了該線程,響應中斷的意思是該線程立刻中斷,而不響應中斷的意思是該線程需要獲取鎖後再中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/623608a5ea9465a9c61191a5f4be7ecf.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"image","attrs":{"src":"https://static001.geekbang.org/infoq/21/21c2ecc5093d05b335499ab1c0d069ee.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"條件隊列","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"人生或許有那麼些不如意。漫長的一個小時排隊等待終於過去了,輪到我們準備做核酸了,你說","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"氣不氣","attrs":{}},{"type":"text","text":",每次叫練妻出門都帶身份證,可偏偏回家這次忘記了?我們用代碼看看叫練一家三口在做核酸的過程中到底發生了啥事情?又是怎麼處理的!","attrs":{}}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"import java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\n/**\n * @author :jiaolian\n * @date :Created in 2021-01-22 16:10\n * @description:條件隊列測試\n * @modified By:\n * 公衆號:叫練\n */\npublic class ConditionTest {\n\n private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();\n\n private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();\n\n //條件隊列\n private static Condition condition = writeLock.newCondition();\n\n //醫院\n private static class Hospital {\n\n private String name;\n\n public Hospital(String name) {\n this.name = name;\n }\n\n //核酸檢測排隊測試\n public void checkUp(boolean isIdCard) {\n try {\n writeLock.lock();\n validateIdCard(isIdCard);\n System.out.println(Thread.currentThread().getName()+\"正在做核酸檢測\");\n //核酸過程...難受...\n Thread.sleep(3000);\n } catch (InterruptedException e) {\n e.printStackTrace();\n } finally {\n writeLock.unlock();\n System.out.println(Thread.currentThread().getName()+\"核酸檢測完成\");\n }\n }\n\n //校驗身份信息;\n private void validateIdCard(boolean isIdCard) {\n //如果沒有身份信息,需要等待\n if (!isIdCard) {\n try {\n System.out.println(Thread.currentThread().getName()+\"忘記帶身份證了\");\n condition.await();\n } catch (InterruptedException e) {\n e.printStackTrace();\n }\n }\n }\n\n //通知所有等待的人\n public void singleAll() {\n try {\n writeLock.lock();\n condition.signalAll();\n } catch (Exception e) {\n e.printStackTrace();\n } finally {\n writeLock.unlock();\n }\n }\n\n }\n\n\n public static void main(String[] args) throws InterruptedException {\n Hospital hospital = new Hospital(\"南京市第一醫院\");\n Thread.currentThread().setName(\"護士小姐姐線程\");\n Thread JLWife = new Thread(()->{\n hospital.checkUp(false);\n },\"叫練妻\");\n JLWife.start();\n //睡眠100毫秒是讓一家三口是有順序的排隊去檢測\n Thread.sleep(100);\n Thread JLSon = new Thread(()->hospital.checkUp(true),\"叫練子\");\n JLSon.start();\n Thread.sleep(100);\n Thread JL = new Thread(()->{\n hospital.checkUp(true);\n },\"叫練\");\n JL.start();\n //等待叫練線程執行完畢\n JL.join();\n hospital.singleAll();\n }\n\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上代碼:一家人獲取獨佔鎖需要排隊檢測,叫練妻先進去準備核酸,護士小姐姐說先要刷身份證才能進去,叫練妻突然回想起來,出門走得急身份證忘記帶了,這可咋辦,需要重新排隊嗎?叫練妻很恐慌,護士小姐姐說,要不這樣吧,你先趕緊回家拿,等叫練子,叫練先檢測完,我就趕緊安排你進去在做核酸,那樣你就不需要重新排隊了,這就是上述這段代碼的表達意思。我們看看執行結果如下圖,和我們分析的結果一致,下圖最後畫紅圈的地方叫練妻最後完成核酸檢測。下面我們看看AQS內部經歷的過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ba/ba010948e44d15bff30add0be31513e1.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"如下圖,當叫練妻先獲取鎖,發現身份證忘帶調用","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"await","attrs":{}},{"type":"text","text":"方法會釋放持有的鎖,並把自己當做node節點放入條件隊列的尾部,此時條件隊列爲空,所以條件隊列中只有叫練妻一個線程在裏面,接着護士小姐姐會將核酸醫生這個資源釋放分配給下一個等待者,也就是叫練子線程,同理,叫練子執行完畢釋放鎖之後會喚醒叫練線程,底層是用LockSupport.unpark來完成喚醒的的操作,相當於基礎系列裏的wait/notify/notifyAll等方法。當叫練線程執行完畢,後面沒有線程了,護士小姐姐調用singleAll方法會見條件隊列的叫練妻線程喚醒,並加入到AQS的尾部,等待執行。其中條件隊列是一個單向鏈表,一個AQS可以通過newCondition()對應多個條件隊列。這裏我們就不單獨用代碼做測試了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b9/b908fe05b058ba2895bf625483567cd5.png","alt":"image.png","title":"image.png","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今天我們用代碼+圖片+故事的方式說明了AQS重要的幾個概念,整理出來希望能對你有幫助,寫的比不全,同時還有許多需要修正的地方,希望親們加以指正和點評,年前這段時間會繼續輸出實現AQS高級鎖,如:ReentrantLock,線程池這些概念等。最後喜歡的請點贊加關注哦。我是","attrs":{}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"user"}},{"type":"strong","attrs":{}}],"text":"叫練【公衆號】","attrs":{}},{"type":"text","text":",邊叫邊練。","attrs":{}}]},{"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","attrs":{}}],"text":"注意:本故事是自己虛構出來的,僅供大家參考理解。希望大家過年都能順利回家團聚!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fa/faa2d2e6f1d9a7cdde4403a1a5a03628.gif","alt":"tempImage1611306633088.gif","title":"tempImage1611306633088.gif","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章