Synchronized和Lock的區(qū)別
并發(fā)編程中篮条,鎖是經(jīng)常需要使用的切端。在開發(fā)中我們常用的鎖有兩種Synchronized和Lock磅轻。
線程安全問題
線程安全是在多線程編程中拐格,有可能會出現(xiàn)同時訪問同一個 共享掉分、可變資源 的情況俭缓,始終都不會導(dǎo)致數(shù)據(jù)破壞以及其他不該出現(xiàn)的結(jié)果。這種資源可以是一個變量酥郭、一個對象华坦、一個文件等。
共享:多個線程可以同時訪問該共享變量不从。
可變:數(shù)據(jù)在生命周期中可以被改變惜姐。
鎖的概念
JAVA 內(nèi)置鎖
隱性鎖:每個JAVA對象可以用作實現(xiàn)同步的內(nèi)置鎖,線程在訪問同步代碼塊時必須先獲取該內(nèi)置鎖椿息,在退出和中斷的時候需要釋放內(nèi)置鎖歹袁。Java內(nèi)置鎖通過synchronized關(guān)鍵字使用,使用其修飾方法或者代碼塊寝优,就能保證方法或者代碼塊以同步方式執(zhí)行条舔。有對象鎖和類鎖(static方法和class上枷鎖)區(qū)分,兩者不沖突可以并行存在乏矾。
顯性鎖:顯式鎖(ReentrantLock)正式為了解決這些靈活需求而生孟抗,ReentrantLock的字面意思是可重入鎖,可重入的意思是線程可以同時多次請求同一把鎖钻心,而不會自己導(dǎo)致自己死鎖凄硼。
鎖的分類
可重入鎖:Synchronized和ReentrantLook都是可重入鎖,鎖的可重入性標(biāo)明了鎖是針對線程分配方式而不是針對方法捷沸。例如調(diào)用Synchronized方法A中可以調(diào)用Synchronized方法B帆喇,而不需要重新申請鎖。
讀寫鎖:按照數(shù)據(jù)庫事務(wù)隔離特性的類比讀寫鎖亿胸,在訪問統(tǒng)一個資源(一個文件)的時候坯钦,使用讀鎖來保證多線程可以同步讀取資源预皇。ReadWriteLock是一個讀寫鎖,通過readLock()獲取讀鎖婉刀,通過writeLock()獲取寫鎖吟温。
可中斷鎖:可中斷是指鎖是可以被中斷的,Synchronized內(nèi)置鎖是不可中斷鎖突颊,ReentrantLock可以通過lockInterruptibly方法中斷顯性鎖鲁豪。例如線程B在等待等待線程A釋放鎖,但是線程B由于等待時間太久律秃,可以主動中斷等待鎖爬橡。
公平鎖:公平鎖是指盡量以線程的等待時間先后順序獲取鎖,等待時間最久的線程優(yōu)先獲取鎖棒动。synchronized隱性鎖是非公平鎖糙申,它無法保證等待的線程獲取鎖的順序,ReentrantLook可以自己控制是否公平鎖船惨。
兩種鎖的底層實現(xiàn)
Synchronized:底層使用指令碼方式來控制鎖的柜裸,映射成字節(jié)碼指令就是增加來兩個指令:monitorenter和monitorexit。當(dāng)線程執(zhí)行遇到monitorenter指令時會嘗試獲取內(nèi)置鎖粱锐,如果獲取鎖則鎖計數(shù)器+1疙挺,如果沒有獲取鎖則阻塞;當(dāng)遇到monitorexit指令時鎖計數(shù)器-1怜浅,如果計數(shù)器為0則釋放鎖铐然。
Lock:底層是CAS樂觀鎖,依賴AbstractQueuedSynchronizer類恶座,把所有的請求線程構(gòu)成一個CLH隊列搀暑。而對該隊列的操作均通過Lock-Free(CAS)操作。
Synchronized和Lock比較
- Synchronized是關(guān)鍵字奥裸,內(nèi)置語言實現(xiàn),Lock是接口沪袭。
- Synchronized在線程發(fā)生異常時會自動釋放鎖湾宙,因此不會發(fā)生異常死鎖。Lock異常時不會自動釋放鎖冈绊,所以需要在finally中實現(xiàn)釋放鎖侠鳄。
- Lock是可以中斷鎖,Synchronized是非中斷鎖死宣,必須等待線程執(zhí)行完成釋放鎖伟恶。
- Lock可以使用讀鎖提高多線程讀效率。