一、前置知識
????????公平鎖和非公平鎖:
????????公平鎖:鎖被釋放以后,先申請的線程先得到鎖。性能較差一些,因為公平鎖為了保證時間上的絕對順序,上下文切換更頻繁
????????非公平鎖:鎖被釋放以后,后申請的線程可能會先獲取到鎖,是隨機或者按照其他優先級排序的。性能更好,但可能會導致某些線程永遠無法獲取到鎖
????????可重入鎖:
????????也叫做遞歸鎖,指的是線程可以再次獲取自己的內部鎖,比如一個線程獲取到了對象鎖,此時這個對象鎖還沒有釋放,當其想再次獲取這個對象鎖的時候還是可以獲取的,如果不可重入的話,會導致死鎖。
????????
????????自旋思想:
????????當線程請求鎖時,如果鎖已經被其他線程持有,那么該線程會不斷地重試獲取鎖,而不是被掛起等待,這種不斷嘗試獲取鎖的行為稱為自旋
????????LockSupport:
????????一個工具類,用于線程的阻塞和喚醒操作,類似于wait()和notify()方法,但是更加靈活和可控提供了park()和unpark()兩個靜態方法用于線程阻塞和喚醒操作。優點在于可以在任意時刻阻塞和喚醒線程而不需要事先獲取鎖或監視器對象。
????????數據結構之雙向鏈表:
????????雙向鏈表(Doubly Linked List)是一種常見的數據結構,它是由一系列結點(Node)組成的,每個結點包含三個部分:數據域、前驅指針和后繼指針。其中,數據域存儲結點的數據,前驅指針指向前一個結點,后繼指針指向后一個結點。通過這種方式,雙向鏈表可以實現雙向遍歷和插入、刪除操作。
????????設計模式之模板設計模式:
????????模板設計模式是一種行為型設計模式,定義了一種算法的框架,并將某些步驟延遲到子類中事先,這種設計模式的主要目的是允許子類在不改變算法結構的情況下重新定義算法中的某些步驟。
????????優點是能夠提高代碼復用性和可維護性。
二、AQS入門級別理論知識
? ? ? ? 1、是什么?
? ? ? ? 字面意思:抽象的隊列同步器
? ? ? ? 通常的AbstractQueuedSynchronizer 簡稱為 AQS。
????????技術解釋:
????????是用來實現鎖或者其他同步器組件的公共基礎部分的抽象實現
????????是重量級基礎框架及整個JUC體系的基石,只要用于解決鎖分配給”誰“的問題。
????????整體就是一個抽象的FIFO隊列來完成資源獲取線程的排隊工作,并通過一個int類變量表示持有鎖的狀態
? ? ? ? 2、AQS為什么是JUC內容中最重要的基石
????????和AQS有關的:
????????ReentrantLock:
????????CountDownLatch:
????????ReentrantReadWriteLock:
????????Semaphore:
????????進一步理解鎖和同步器的關系:
????????鎖,面向鎖的使用者:定義了程序員和鎖交互的使用層API,隱藏了實現細節,你調用即可同步器,面向鎖的實現者。
????????Java并發大神DoungLee,提出了統一規范并簡化了鎖的實現,將其抽象出來,屏蔽了同步狀態管理、同步隊列的管理和維護、阻塞線程排隊和通知、喚醒機制等,是一切鎖和同步組件實現的----公共基礎部分
? ? ? ? 3、能干嘛?
????????加鎖會導致阻塞------有阻塞就需要排隊,實現排隊必然需要隊列
????????搶到資源的線程直接使用處理業務,搶不到資源的必然涉及一種排隊等候機制。搶占失敗的線程繼續去等待(類似于銀行辦理窗口都滿了,暫時沒有受理窗口的顧客只能去候客區排隊等待),但等候線程仍然保留獲取鎖的可能且獲取鎖流程仍在繼續(候客區的顧客也在等著叫號,輪到了再去受理窗口辦理業務)
????????
????????既然說到了排隊等候機制,那么就一定會有某種隊列形成,這樣的隊列是什么數據結構呢?
????????如果共享資源被占用,就需要一定的阻塞等待喚醒機制來保證鎖分配。這個機制主要用的是CLH隊列的變體實現的,將暫時獲取不到鎖的線程加入到隊列中,這個隊列就是AQS同步隊列的抽象表現。它將要請求共享資源的線程及自身的等待狀態封裝成隊列的節點對象(Node),通過CAS、自旋以及LockSupport.park()的方式,維護著state變量的狀態,使其達到同步的狀態。
? ? ? ? 4、小總結
????????AQS同步隊列的基本結構:
????????內部類Node(Node類在AQS類內部)
????????Node的int變量
????????Node的等待狀態waitState成員變量:volatile int waitStatus;
????????等候區其它顧客(其它線程)的等待狀態。隊列中每個排隊的個體就是一個Node
????????Node此類的講解:
三、AQS源碼分析前置知識儲備
? ? ? ? 1、AQS內部體系架構圖
? ? ? ? 2、AQS內部體系架構----AQS自身
????????AQS的int類型變量state:
????????AQS的同步狀態State成員變量
? ? ? ?
????????
????????銀行辦理業務的受理窗口狀態:
????????零就是沒人,自由狀態可以去辦理
????????大于等于1,有人占用窗口,等著去
????????AQS的CLH隊列:
????????CLH(三個大牛的名字組成)隊列為一個雙向隊列
????????銀行候客區的等待顧客
? ? ? ? 小總結:
????????有阻塞就需要排隊,實現排隊必然需要隊列
????????State變量+CLH雙端隊列
? ? ? ? 3、AQS內部體系架構----內部類Node
????????Node的int變量:
????????Node的等待狀態waitState成員變量
????????
????????說人話:
????????等候區其他顧客(其他線程)的等待狀態
????????隊列中每個排隊的個體就是一個Node
????????Node此類的講解:
????????內部結構:
????????
????????屬性說明:
四、AQS源碼深度講解和分析
? ? ? ? 1、ReentrantLock的原理
????????Lock接口的實現類,基本都是通過聚合了一個隊列同步器的子類完成線程訪問控制的
? ? ? ? 2、從最簡單的lock方法開始看看公平和非公平
公平鎖和非公平鎖的lock()方法唯一的區別就在于公平鎖在獲取同步狀態時多了一個限制條件:hasQueuedPredecessors()-----公平鎖加鎖時判斷等待隊列中是否存在有效節點的方法
? ? ? ? 3、以非公平鎖ReentrantLock()為例作為突破走起---方法lock()
????????對比公平鎖和非公平鎖的tryAcquire()方法的實現代碼,其實差異就在于非公平鎖獲取鎖時比公平鎖中少了一個判斷!hasQueuedPredecessors(),hasQueuedPredecessors()中判斷了是否需要排隊,導致公平鎖和非公平鎖的差異如下:
????????公平鎖:公平鎖講究先來后到,線程在獲取鎖時,如果這個鎖的等待隊列中已經有線程在等待,那么當前線程就會進入到等待隊列中;
????????非公平鎖:不管是否有等待隊列,如果可以獲取到鎖,則立刻占有鎖對象。也就是說隊列的第一個排隊線程蘇醒后,不一定就是排頭的這個線程獲得鎖,它還需要參加競爭鎖(存在線程競爭的情況下),后來的線程可能不講武德插隊奪鎖了。
????????正式開始源碼解讀:
????????lock():
? ? ??
????????acquire():
????????tryAcquire(arg):
????????return false:繼續推進條件,走下一個方法
????????return true:結束
????????addwaiter(Node.EXCLUSIVE):
????????注意:在雙向鏈表中,第一個節點為虛節點(也叫做哨兵節點),其實不存儲任何信息,只是占位。真正的第一個有數據的節點,是從第二個節點開始的
????????假如此時有線程C進入:
????????acquireQueued(addWeiter(Node.EXCLUSIVE), arg)-----坐穩隊列:
????????