1、synchronized 是Java內(nèi)置的關(guān)鍵字,使用后會自動釋放鎖,
Lock是java.util.concurrent.Locks 包下的一個接口,必須要手動釋放。特別是在發(fā)生異常時,需要在 finally 塊中進(jìn)行手動釋放,否則會發(fā)生死鎖行為
synchronized 代碼清單
Lock 代碼清單
2、Lock可響應(yīng)中斷,而synchronized 不能響應(yīng)中斷,并且Lock提供了更豐富的方法實現(xiàn);例如
Lock() ; //獲取鎖
tryLock(); //獲取鎖
tryLock(long time, TimeUnit unit); //在一定時間單位內(nèi)等待
lockInterruptibly(); //獲取鎖,可響應(yīng)中斷(AB線程同時獲取鎖,A得到后,B進(jìn)行等待,則B會被Tread.interrupt()方法中端并可去執(zhí)行其他的代碼邏輯,而synchronized無法被中端)
unlock(); //釋放鎖
***以下對lockInterruptibly 進(jìn)行簡單的驗證,代碼結(jié)構(gòu)糙,只為驗證***
3、synchronized 是非公平鎖,即不能保證等待鎖線程的順序,
Lock的實現(xiàn) ReentrantLock 可通過實例化true or false 的構(gòu)造參數(shù)實現(xiàn)公平鎖和非公平鎖,默認(rèn)為非公平鎖
ReentrantLock的構(gòu)造參數(shù)
4、ReentrantLock是唯一實現(xiàn)了Lock接口的類,并且ReentrantLock提供了更多的方法
lck.isFair();
lck.isLocked();
lck.getHoldCount();
lck.getQueueLength();
lck.wait();
...
5、synchronized無法判斷是否獲取鎖的狀態(tài),Lock可以判斷是否獲取到鎖;
6、Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。
7、都是可重入鎖:在執(zhí)行對象中所有同步方法不用再次獲得鎖
8、synchronized是一個悲觀鎖,Lock是一個樂觀鎖(底層基于volatile和cas實現(xiàn)),
二、底層實現(xiàn)
1、synchronznized映射成字節(jié)碼指令就是增加兩個指令:monitorenter、monitorexit,
當(dāng)一條線程執(zhí)行時遇到monitorenter指令時,它會嘗試去獲得鎖,如果獲得鎖,那么所計數(shù)器+1(為什么要加1,因為它是可重入鎖,可根據(jù)這個瑣計數(shù)器判斷鎖狀態(tài)),如果沒有獲得鎖,那么阻塞,
當(dāng)它遇到一個monitoerexit時,瑣計數(shù)器會-1,當(dāng)計數(shù)器為0時,就釋放鎖
(tips:節(jié)碼中出現(xiàn)的兩個monitoerexit指令的原因是:一個正常執(zhí)行-1,令一個異常時執(zhí)行,這兩個用goto的方式只執(zhí)行一個)
2、Lock底層則基于volatile和cas實現(xiàn)