一肩袍、為什么需要鎖
存在共享數(shù)據(jù)中贝。
當(dāng)出現(xiàn)ConcurrentModificationException的時候等太,存在多個線程對一個集合同時進行遍歷或者修改。
單線程就不需要考慮這種情況规哲。
二播赁、解決方案
當(dāng)前類中涉及集合修改和遍歷操作加上synchronized關(guān)鍵字庐氮,或者是這兩個邏輯放在一個線程中完成膘茎。
1、可重入&&互斥
synchronized是可重入鎖脚草;ReentrantLock也是赫悄。
即同一個線程可以輸出Hello World不會死鎖。
// 可重入
public void syncsTask() {
synchronized (this) {
System.out.println("Hello");
synchronized (this){
System.out.println("World");
}
}
}
synchronized是互斥鎖,滿足互斥性(操作的原子性)埂淮,可見性嚼贡。
synchronized鎖的不是代碼,是對象同诫。
同步代碼塊synchronized(this)和同步方法鎖的是同一個對象粤策。
類鎖和對象鎖是互不干擾的。只有使用同一把鎖線程之間才會干擾误窖。
Java對象頭中都存在一個Monitor對象叮盘,這也是Java中任意對象可以作為鎖的原因。
2霹俺、為什么很多人對它嗤之以鼻
早前版本是重量級鎖柔吼,依賴于系統(tǒng)的Mutex Lock(互斥),線程之間切換從用戶態(tài)轉(zhuǎn)換至核心態(tài)丙唧,開銷大愈魏。
jdk6之后性能已經(jīng)提升。
3想际、自旋鎖與自適應(yīng)自旋鎖
jdk6默認(rèn)開啟培漏,不掛起線程,但如果鎖占用時間過長胡本,就不再推薦使用了牌柄。
讓線程處于忙循環(huán)等待鎖釋放,不出讓CPU侧甫,減少線程的切換珊佣。
4、鎖消除
JIT編譯時披粟,對運行上下文進行掃描咒锻,去除不可能存在競爭的鎖。
5守屉、鎖粗化
JVM對鎖的范圍進行擴大惑艇,減少鎖同步的代價。
6胸梆、synchronized的四個演變階段
鎖膨脹的方向:無鎖敦捧、偏向鎖须板、輕量級鎖碰镜、重量級鎖
偏向鎖:CAS,指一段同步代碼一直被一個線程所訪問习瑰,那么該線程會自動獲取鎖绪颖,降低獲取鎖的代價
輕量級鎖:偏向鎖升級而來,適用于線程交替執(zhí)行同步塊,自旋
重量級鎖:同步塊或者方法執(zhí)行時間較長柠横,追求吞吐量
三窃款、synchronized和static synchronized區(qū)別
一個鎖的是類對象,一個鎖的是實例對象牍氛。
若類對象被lock晨继,則類對象的所有同步方法(static synchronized 修飾)全被lock;
若實例對象被lock搬俊,則該實例對象的所有同步方法(synchronized 修飾)全被lock紊扬。
每個synchronized方法都必須獲得調(diào)用該方法的類實例的”鎖“方能執(zhí)行,否則所屬線程阻塞唉擂。
方法一旦執(zhí)行餐屎,就會獨占該鎖,一直到從該方法返回時才將鎖釋放玩祟,此后被阻塞的線程方能獲得該鎖腹缩,從而重新進入可執(zhí)行狀態(tài)。這種機制確保了同一時刻對于每一個類的實例空扎,其所有聲明為synchronized的成員函數(shù)中之多只有一個處于可執(zhí)行狀態(tài)
藏鹊,從而有效避免了類成員變量的訪問沖突。
四转锈、synchronized方法與synchronized代碼塊
private synchronized void syncFunc() {
// do something
}
private void syncBlockFunc() {
synchronized (this) {
// do something
}
}
synchronized methods() {}與synchronized(this){}之間沒有什么區(qū)別伙判,只是synchronized methods() {} 便于閱讀理解,而synchronized(this){}可以更精確的控制沖突限制訪問區(qū)域黑忱,有時候表現(xiàn)更高效率宴抚。
五、synchronized和ReentrantLock區(qū)別
所屬不同關(guān)鍵字甫煞,類菇曲。
底層實現(xiàn)不同MarkWord,Unsafe類抚吠。
ReentrantLock可以選擇公平(fair)鎖(排隊打飯)和非公平鎖常潮,構(gòu)造函數(shù)傳入true;
synchronized是非公平的(堵車時的加塞)楷力。
// 一般通常會使用try catch finally方式
public class ReentrantLockDemo implements Runnable {
private static ReentrantLock lock = new ReentrantLock(false);
@Override
public void run() {
while (true) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get lock");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
break;
} finally {
lock.unlock();
}
}
}
將synchronized轉(zhuǎn)換為直觀可控的對象行為喊式。