synchronized和lock鎖區(qū)別
- synchronized是關鍵字,lock是juc包下的一個接口芝囤。
- synchronized和lock都是可重入的质和。
- synchronized是公平鎖队魏,lock支持公平和非公平兩種限寞。
- synchronized是不可中斷的,lock是可中斷的砰琢。
- lock可以通過 tryLock方法設置超時時間蘸嘶,lock加鎖之后一定要手動釋放鎖,且lock可以判斷鎖的狀態(tài)氯析。
synchronized實現(xiàn)原理
synchronized鎖是基于對象實現(xiàn)的亏较,對象存儲在堆中,每個對象會有一個對象頭掩缓,對象頭里面會有一個markword來記錄當前鎖的一個狀態(tài):無鎖(匿名偏向)雪情、偏向鎖、輕量級鎖你辣、重量級鎖巡通。
鎖升級過程:當線程訪問synchronized同步代碼塊時尘执,會先嘗試加偏向鎖,如果加成功直接返回宴凉;失敗就說明當前已經有別的線程獲取了鎖誊锭,就會嘗試升級成輕量級鎖,線程會使用cas自旋一定次數來獲取鎖弥锄,如果還是獲取鎖失敗就會升級成重量級鎖丧靡,此時線程就會進入block狀態(tài)。
在jdk1.6之前籽暇,synchronized只有重量級鎖温治。在jdk1.6之后增加了鎖升級的機制,另外還增加了鎖消除和鎖膨脹的優(yōu)化:
- 鎖消除:synchronized同步代碼塊中沒有臨界資源的訪問戒悠,不在加鎖熬荆。
- 鎖膨脹:for循環(huán)中使用synchronized加鎖,就會導致頻繁的加鎖和釋放鎖绸狐,為了避免不必要的鎖資源消耗卤恳,就會擴大鎖的范圍。
lock實現(xiàn)原理
lock底層是基于AQS實現(xiàn)寒矿。AQS是抽象隊列同步器突琳,是一個用來構建鎖和同步器的框架。
AQS關鍵數據結構
- state:同步變量符相,使用volatile關鍵字修飾本今,表示鎖的狀態(tài),state=0代表當前沒有加鎖主巍,大于0表示有線程加鎖。
- 等待隊列:加鎖失敗的線程會進入到等待隊列中挪凑。等待隊列是個雙向鏈表孕索,每個node節(jié)點有前繼和后繼節(jié)點,等待鎖的線程躏碳,以及等待狀態(tài)搞旭。
加鎖過程
- 非公平鎖:線程會先直接使用cas的方式去修改state變量(從0修改成1),如果修改成功菇绵,則表示該線程獲得了鎖肄渗。否則表示加鎖失敗,線程加入到等待隊列中咬最,線程會被掛起/阻塞翎嫡。
- 公平鎖:線程會先判斷等待隊列中是否為空,等待隊列不為空直接進等待隊列排隊永乌;等待隊列為空才會使用cas嘗試去修改state變量獲得鎖惑申,cas失敗進等待隊列排隊具伍。
釋放鎖過程
線程使用cas的方式將state減1,如果state等于0圈驼,表示鎖釋放人芽。喚醒隊列第一個線程,喚醒之后隊列第一個線程通過cas的方式嘗試加鎖绩脆,一旦加鎖成功萤厅,就會把自己移除隊列,讓下一個節(jié)點變成對頭靴迫,然后該線程就可以去執(zhí)行邏輯了惕味。
AQS喚醒節(jié)點時,為何從后往前找第一個節(jié)點
因為等待隊列添加節(jié)點(以及節(jié)點取消)時矢劲,是先調整新節(jié)點的前向指針赦拘,再調整tail指針(此時原來tail指針的next指針還是null),最后在調整原來tail的next指針芬沉,如果從前往后找躺同,會存在節(jié)點丟失(沒訪問到)的情況。