引用自:http://blog.iluckymeeting.com/2018/01/06/threadandlockone/
什么是鎖?
在多線程編程領(lǐng)域,基本上所有的編程模型都采用了“并發(fā)訪問串行處理”的策略卧秘,而方法就是給臨界資源加一把鎖。
為什么加鎖?
我們把多個線程競爭處理的資源稱為臨界資源(代碼塊颁井、方法體等),根據(jù)“并發(fā)訪問串行處理”的策略,當一個線程獲得了臨界資源的使用權(quán)以后蠢护,其它線程必須等這個線程處理完以后才能通過競爭再次嘗試獲得臨界資源的使用權(quán)雅宾,為了保證臨界資源只由一個線程獲得,需要給臨界資源加鎖葵硕,線程要獲得臨界資源使用權(quán)必須先競爭鎖眉抬,一旦線程獲得了鎖,則其它線程就無法再獲得同一把鎖懈凹,必須等待這個鎖被解鎖釋放蜀变,才能再次競爭嘗試獲得這把鎖,一旦加鎖成功意味著線程獲得了臨界資源使用權(quán)介评。
如此這個問題就好理解了库北,要獲得臨界資源爬舰,就要先給資源加鎖,哪個線程加鎖成功寒瓦,就代表著它暫時獲得了臨界資源的獨享權(quán)情屹,別的線程需要等待臨界資源被解鎖才能再次嘗試競爭臨界資源。
加鎖的原理是什么杂腰?
要給臨界資源加鎖垃你,常見的方式是使用synchronized關(guān)鍵字或Lock接口的各種實現(xiàn)(常用ReentrantLock),在本質(zhì)上都是通過給某個對象實例加鎖實現(xiàn)臨界資源的鎖定喂很,而給對象實例加鎖就用到了每個對象都有的一個數(shù)據(jù)結(jié)構(gòu)對象頭惜颇。先來看一下對象頭的存儲結(jié)構(gòu):
對象頭有這么幾個特點:
- 如果這個對象是個數(shù)組,則對象頭將占用3個機器碼恤筛,如果不是數(shù)組官还,對象頭將占用2個機器碼(32bit)。
- 由于對象頭里存儲的是與對象數(shù)據(jù)無關(guān)的信息毒坛,為了提高空間利用率望伦,對象頭的存儲結(jié)構(gòu)不是固定的,當對象處于不同的狀態(tài)時,存儲結(jié)構(gòu)有所區(qū)別
鎖的分類
如果從不同的用途和維度來看,會有多種不同的鎖定義饲化,下面列舉幾種常見的鎖定義:
- 公平鎖、非公平鎖
- 自旋鎖劣摇、自適應自旋鎖
- 讀寫鎖
- 偏向鎖、輕量級鎖弓乙、重量級鎖
公平鎖末融、非公平鎖
所謂公平鎖就是線程獲得鎖的順序和線程請求鎖的順序相同,相反非公平鎖就是線程請求鎖的順序并不影響線程獲得鎖的順序暇韧。
要想保證線程獲得鎖的順序性勾习,必然要花費一些資源去維護這個順序,所以公平鎖相比于非公平鎖效率有所下降懈玻。synchronized實現(xiàn)就是非公平鎖巧婶,ReentrantLock默認也是采用非公平鎖,不過可以指定使用公平鎖涂乌。
自旋鎖艺栈、自適應自旋鎖
在JDK1.6以前(這個記不清了),線程如果競爭鎖失敗會進入阻塞狀態(tài)湾盒,當鎖被釋放后湿右,重新進入喚醒狀態(tài)再次嘗試競爭鎖。線程在阻塞態(tài)和喚醒態(tài)之間切換需要通過操作系統(tǒng)的Metux Lock在用戶態(tài)和內(nèi)核態(tài)之間切換罚勾,如果鎖被占用的時間很短毅人,那么這個狀態(tài)切換所消耗的資源在整個處理過程中所占的比例就偏高漾唉,這樣就比較浪費了,為了解決這個問題堰塌,引入了自旋鎖。
所謂自旋鎖就是當線程競爭鎖失敗時分衫,不進入阻塞狀態(tài)场刑,而是執(zhí)行一段無意義的計算空轉(zhuǎn)一下,JVM默認自旋10次蚪战,不過可以通過參數(shù)修改這個值牵现。自旋鎖雖然提高了效率,但是通過分析發(fā)現(xiàn)邀桑,往往線程自旋失敗以后瞎疼,鎖就被釋放了,也就是說如果線程能夠自旋12次就很有可能獲得鎖壁畸,于是又引入了JVM動態(tài)調(diào)整自旋次數(shù)的自適應自旋鎖贼急。當一個線程競爭鎖成功以后,JVM認為它再次競爭鎖成功的概率比較大捏萍,于是JVM將它的自旋次數(shù)調(diào)高太抓,相反如果一個線程競爭鎖失敗了,JVM認為它下次競爭成功的概率仍然較小令杈,于是調(diào)小它的自旋次數(shù)走敌,避免過多的無效自旋浪費計算資源。
讀寫鎖
有些場景下線程競爭鎖只是想做讀取操作逗噩,并不會修改共享數(shù)據(jù)掉丽,這種情況下如果使用排它鎖讓線程一個一個的去讀顯然不是最好的選擇,于是出現(xiàn)了讀寫鎖,ReadWriteLock就是讀寫鎖定義接口异雁。通過讀寫鎖捶障,多個線程可以同時給臨界資源加讀鎖,完成讀操作片迅。
- 當臨界資源被加了讀鎖残邀,則其它線程可以再次給臨界資源加讀鎖
- 當臨界資源被加了讀鎖,其它線程如果要加寫鎖柑蛇,必須等讀鎖被釋放
- 當臨界資源被加了寫鎖芥挣,其它線程如果要加讀鎖或?qū)戞i,必須等待鎖被釋放
偏向鎖耻台、輕量級鎖空免、重量級鎖
這是比較重要的一個鎖定義了,它們對資源的消耗及效率都是由低到高盆耽,偏向鎖遇到競爭時會膨脹成輕量級鎖蹋砚,輕量級鎖在自旋失敗時會膨脹成重量級鎖扼菠,而且鎖的膨脹是單向不可逆的,它們的實現(xiàn)都需要通過對象頭結(jié)構(gòu)坝咐,后面單獨寫一篇詳細介紹循榆。