多線程AQS

我們在多線程編程中或多或少的會用到鎖,最普遍的應用就是sychronized,但是其自身的非公平鎖,可重入鎖的特性,使其無法適應複雜的業務場景,例如公平鎖,讀寫鎖等等,而我們的jdk提供了AbstractQueuedSynchronizer(此後簡稱AQS),使我們可以進行擴展實現不同類型的鎖以滿足業務場景的需求。JDK提供的CountDownLatch,CyclicBarrier,ReentrantLock,Readwritelock,Semaphore,以及Condition都用到了類似AQS這個抽象類,這裏我們就爲大家解讀下AQS源碼,並從源碼角度分析以上這幾種鎖的實現方式。廢話不多說直接上圖:
在這裏插入圖片描述
其實變量並不多可以大致分爲3類,head,tail,鏈表的元素,每個線程都可以是該鏈表的一個節點,state鎖的狀態,unsafe及其以下的成員變量是通過反射直接內存數據的操作。而其中大量的方法無非也就是對鏈表的操作和state的修改,而state可以是重入鎖的重入次數,也可以使讀寫鎖讀鎖數量和寫鎖數量(前八位讀數後八位寫數,總之state是萬能的),而爲了滿足鎖的原子性採用的一些CAS操作。
Condition 替代了傳統Lock,Lock的wait notify需要配合sychronized使用,而Condition省去了這些還進行了一些擴展入notifyAll等。
ReentrantLock可重入鎖,又稱作獨佔鎖,一個標識位標識線程,一個標識位標識重入次數,只有線程標識位爲空其他線程纔可以獲取鎖。
Readwritelock讀寫鎖,分爲兩部分讀鎖和寫鎖。讀鎖爲共享鎖,寫鎖爲獨佔鎖。獲取寫鎖時先判斷讀鎖數量如果>0無法獲取,獲取讀鎖時如果寫鎖數量>0並且讀鎖不是當前線程無法獲取,然後進入等待隊列直到被喚醒,在編程時候注意鎖降級(在釋放寫鎖前先獲取讀鎖可以節省不必要的開銷)。
在CountDownLatch中,此時state用來標記通信線程的數量,只有指定數量的的線程都countdown()後纔會釋放鎖,此時循環鎖也就是對外暴露的wait()所在的線程纔會繼續執行。
CyclicBarrier採用ReentrantLock和condition實現分批次運行,只有指定數量的線程都執行到await()方法後纔會繼續執行,其餘線程進入等待隊列。
Semaphore又叫令牌桶,時常高併發訪問中被用作限流同一時間只能有指定數量的線程執行,其餘線程唄放入等待隊列。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章