synchronized的特性
1. 樂觀鎖/悲觀鎖自適應,開始時是樂觀鎖,如果鎖沖突頻繁,就轉換為悲觀鎖
2.輕量級/重量級鎖自適應 開始是輕量級鎖實現,如果鎖被持有的時間較長,就轉換成重量級鎖
3.自旋/掛起等待鎖自適應
4.不是讀寫鎖
5.非公平鎖
6,可重入鎖
synchronized的使用
1)直接修飾普通方法
鎖的是對象(單個對象內部加鎖):
public class SynchronizedDemo {public synchronized void methond() {}
}
(2)修飾靜態方法
鎖的是類的所有對象:
public class SynchronizedDemo {public synchronized static void method() {}
}
(3)修飾代碼塊
明確指定鎖哪個對象:
鎖當前對象:
public class SynchronizedDemo {public void method() {synchronized (this) {}}
}
鎖類對象:
public class SynchronizedDemo {public void method() {synchronized (SynchronizedDemo.class) {}}
}
只有兩個線程競爭同一把鎖,才會有鎖沖突,才會產生阻塞等待。
synchronized的鎖機制
1.鎖升級
JVM將synchronized鎖分為?鎖、偏向鎖、輕量級鎖、重量級鎖狀態。會根據情況,進?依次升
級。
1.偏向鎖階段
核心思想:懶漢模式,能不加鎖就不加鎖,能晚加鎖則晚加鎖
偏向鎖:并非真正加鎖了,而是做了非常輕量的標記
一旦其他線程來和我競爭這個鎖,就在另一個線程之前,先把鎖獲取到
從偏向鎖升級到輕量級鎖(真正加鎖,有互斥)
沒有競爭,就把加鎖省略
非必要不加鎖
在遇到競爭的情況下,偏向鎖沒有提升效率,但是如果在沒有競爭的情況下,偏向鎖就大幅度提升效率
2.輕量級鎖階段
有競爭但不多? ?通過自旋鎖方式實現
優:另外的線程把鎖釋放了,就會第一時間拿到鎖
劣:比較耗CPU
與此同時,synchronized內部也會統計 當前這著鎖對象,有多少個線程在參與競爭,這里當發生參與競爭的線程比較多了,就會進一步升級到重量級鎖
對于自旋鎖來說,如果同一個鎖競爭者很多,大量的線程都在自旋,整體CPU的消耗就很大
?3.重量級鎖階段
此時拿不到鎖的線程就不會繼續自旋了,而是進行"阻塞等待",就會讓出CPU了(不會使CPU占用率太高)
當當前線程釋放鎖的時候,就由系統隨機喚醒一個線程隨機喚醒一個線程來獲取鎖
2.鎖消除
也是synchronized 中內置的優化策略
編譯器優化中的一種方式,編譯器編譯代碼的時候,如果發現這個代碼,不需要加鎖,就會自動化把鎖干掉
鎖消除,針對一眼看上去就完全不涉及線程安全問題的代碼,能夠把鎖消除掉
偏向鎖,運行起來才知道有沒有鎖沖突
?3.鎖粗化
會把多個細粒度的鎖,合并成一個粗粒度的鎖
synchronized{} 大括號里包含的代碼越少,就認為鎖的粒度越細,包含的代碼越多,就認為鎖的粒度越粗
通常情況下,是更偏好于讓鎖的粒度細一點,更有利于多個線程并發執行的.但是有的時候,是希望鎖的粒度粗點也挺好
?總結:
1.鎖升級:偏向鎖-> 輕量級鎖->重量級鎖
2.鎖消除:自動干掉不必要的鎖
3.鎖粗話:把多個細粒度的鎖合并成一個粗粒度的鎖,減少鎖競爭的開銷