? ? 本文來說一說鎖的各個類型以及之間的差異世蔗。
樂觀鎖與悲觀鎖
? ? 樂觀鎖和悲觀鎖是在數(shù)據(jù)庫中引入的名詞,但在java的并發(fā)鎖中也使用了樂觀鎖和悲觀鎖的思想昼汗。
? ? 樂觀鎖尸诽,認為數(shù)據(jù)在一般情況下不會造成沖突,所以在對數(shù)據(jù)進行讀操作的時候不會加排它鎖绑改,而是在進行數(shù)據(jù)寫的時候馋缅,才會對數(shù)據(jù)沖突與否進行檢測,也就是加排他鎖绢淀。由于樂觀鎖是在提交時才鎖定,所以不會產(chǎn)生任何死鎖瘾腰。juc中CopyOnWriteArrayList就使用了樂觀鎖的思想皆的,寫時加鎖,讀時復制不加鎖蹋盆,在后面的文章會對CopyOnWriteArrayList原理以及源碼進行說明费薄,敬請期待硝全。
? ? 悲觀鎖,相對于樂觀鎖楞抡,悲觀鎖對數(shù)據(jù)被修改持保守態(tài)度伟众,它任務數(shù)據(jù)很容易被修改,所有在數(shù)據(jù)處理前就對數(shù)據(jù)加排他鎖召廷,并在整個處理的過程中都持有該鎖凳厢。
公平鎖與非公平鎖
? ? 通過線程搶占鎖的機制,鎖可以分為公平鎖和非公平鎖竞慢。
? ? 公平鎖先紫,線程在獲取鎖的順序是按照線程請求鎖的時間早晚來決定的,也就是先請求鎖的線程會先獲取到鎖筹煮,也就是FIFO(先進先出)隊列原理遮精。
? ? 非公平鎖,線程在獲取鎖的順序不一定按照請求的早晚來決定败潦,先請求鎖的線程和正在請求鎖的線程本冲,不一定哪個線程會先獲得鎖,這里比較的是正在請求鎖的線程和阻塞隊列中的第一個線程劫扒,后面的文章會講解什么是阻塞隊列檬洞?為什么是比較正在請求鎖的線程和阻塞隊列中的第一個線程而不是阻塞隊列中的所有線程?
? ? java中使用公平鎖和非公平鎖的方式
公平鎖:ReentrantLock pairLock = new ReentrantLock(true);??
非公平鎖:ReentrantLock unpairLock = new ReentrantLock(false);?//false參數(shù)可不傳粟关,默認為false
? ? 建議疮胖,在沒有公平性需求的前提下盡量使用非公平鎖,因為公平鎖會帶來一些性能上的開銷闷板。
獨占鎖與共享鎖
? ? 從鎖是否可以被多個線程獲取的角度澎灸,可以將鎖分為獨占鎖與共享鎖,
? ? 獨占鎖遮晚,保證只能有一個線程獲取到鎖性昭,其他線程獲取鎖的時候就只能被阻塞掛起,排他鎖說的也就是獨占鎖县遣。ReentrantLock類使用的就是獨占鎖的思想糜颠。
? ? 共享鎖,運行多個線程同時獲取同一把鎖萧求,ReentrantReadWriteLock讀寫鎖其兴,就是使用了共享鎖的思想。
可重入鎖? ??
? ? 上面提到了獨占鎖夸政,當一個線程獲取到鎖之后其他線程想獲取鎖時都會被阻塞掛起元旬,那么問題來了,當已獲得鎖的線程再次獲得同一把鎖,該線程會被阻塞掛起嗎匀归?不會被阻塞掛起那這把鎖就是可重入鎖坑资,否則為非可重入鎖。
自旋鎖? ??
? ? 前面提到的鎖都是在獲取不到鎖資源的時候都會被阻塞掛起穆端,一旦阻塞掛起就會發(fā)生上下文切換袱贮,這就會造成性能的損耗。那么自然就會想到在一次獲取不到鎖的時候体啰,能不能多獲取幾次攒巍,從而避免阻塞掛起。自旋鎖就是這樣的思想狡赐,當獲取不到鎖資源的時候窑业,線程不會馬上阻塞掛起,在不放棄CPU使用權(quán)的情況下枕屉,多次嘗試獲取常柄。
? ? 自旋鎖是使用CPU時間換區(qū)線程阻塞掛起上下文切換損耗,但在鎖搶占嚴重的情況下有可能多次獲取鎖都獲取不到最終還是被阻塞掛起搀擂,這樣既消耗的CPU時間又沒有避免上下文切換西潘,所以在鎖搶占嚴重的情況下可以多考慮一下。
? ??? ?今天的分享就到這哨颂,有看不明白的地方一定是我寫的不夠清楚喷市,所有歡迎提任何問題以及改善方法。