一、序言
在并發編程中,synchronized鎖因其使用簡單,在執行緒間同步被廣泛應用,下面對其原理及鎖升級程序進行探究,
二、如何使用
1、修飾實體方法
當實體方法被synchronized修飾時,通過當前實體呼叫此方法的所有執行緒共用一把鎖,不同物件呼叫此方法執行緒間互不影響,
public class A {
public synchronized void func() {
}
}
當使用synchronized鎖修飾實體方法,鎖添加在當前類的實體上,有多少個實體可添加多少把鎖,
2、修飾代碼塊
修飾代碼塊比修飾方法顆粒度更小,當實體方法代碼塊被synchronized修飾時,通過當前實體呼叫此方法的所有執行緒共用一把鎖,不同物件呼叫此方法執行緒間互不影響,
public class B {
public void func() {
synchronized (this) {
}
}
}
當使用synchronized鎖修飾代碼塊,鎖添加在當前類的實體上,有多少個實體可添加多少把鎖,
3、修飾靜態方法
當靜態方法被synchronized修飾時,整個JVM所有呼叫此方法的執行緒均受同一個鎖的約束,
public class C {
public static synchronized void func() {
}
}
當使用synchronized鎖修飾靜態方法,鎖添加在當前類的類物件上,最多添加一把鎖,
非必要不使用synchronized修飾靜態方法
三、鎖的升級
Java 8所使用的synchronized鎖是經過優化后的,存在偏向鎖、輕量級鎖、重量級鎖等狀態,
(一)偏向鎖
執行緒間不存在鎖的競爭行為,至多只有一個執行緒有獲取鎖的需求,常見場景為單執行緒程式,
1、識別方法
判斷是不是偏向鎖的標識是查看呼叫此方法的執行緒是否有且僅有一個,
在多執行緒編程里,被鎖修飾的方法僅被單一執行緒呼叫幾乎不存在,因此偏向鎖比較雞肋:如果能夠明確單一執行緒呼叫目標方法,使用無鎖編程更為合適,
2、性能比較
無鎖與偏向鎖的性能差異非常接近,幾乎可以忽略不計,
(二)輕量級鎖
執行緒間存在鎖的偽競爭行為,即同一時刻絕對不會存在兩個執行緒申請獲取鎖,各執行緒盡管都有使用鎖的需求,但是是交替使用鎖,
1、識別方法
當有兩個及以上執行緒呼叫被鎖修飾的方法時,那么至少能確定是輕量級鎖,
2、性能比較
輕量級鎖由于同一時刻不存在兩個執行緒互相競爭鎖,因此不存在執行緒阻塞-喚醒的背景關系切換,因此性能相對重量級鎖要高很多,
(三)重量級鎖
執行緒間存在鎖的實質性競爭行為,執行緒間都有獲取鎖的需求,但是時間不可交錯,互斥鎖的阻塞等待,
1、識別方法
當能夠肯定至少有兩個及以上執行緒呼叫被鎖修飾的方法時,執行緒呼叫方法是隨機的,那么大概率是重量級鎖,
2、性能比較
重量級鎖由于涉及到執行緒阻塞-喚醒的背景關系切換,造成相比較與無鎖狀態,效率低很多,
四、其它內容
(一)鎖的性質
1、公平性
synchronized鎖是非公平鎖,沒有FIFO佇列機制保障競爭鎖的執行緒一定有幾率獲得鎖,
2、重入性
synchronized鎖是可重入鎖,可重入意味著嵌套呼叫不會產生死鎖問題,
3、樂(悲)觀鎖
synchronized鎖是一種悲觀鎖,通過加鎖實作執行緒間同步,
(二)理解重量級鎖
在多執行緒環境下,如果使用synchronized鎖,那么大概率會升級到重量級鎖,偏向鎖和輕量級鎖非刻意為之,很難存在,更大的意義是對比幫助理解重量級鎖的性能,
重量級鎖盡管會對性能產生很大影響,但是依舊是解決執行緒間同步的有效手段,
1、選用鎖的建議
當被鎖修飾的方法或者代碼塊執行時間較長時,選用基于執行緒阻塞-喚醒切換背景關系的方式進行執行緒同步效率相對較高,
當被鎖修飾的方法或者代碼塊執行時間較短時,應選用其它替代鎖,比如自旋鎖等,
(三)理解synchronized鎖
在實際多執行緒場景開發中,synchronized鎖大概率會升級到重量級鎖,因其單向升級的特點,重量級狀態的synchronized鎖可能會對實際業務的并發產生不利影響,手動選用其它鎖可能會更合適,
synchronized鎖僅可用于解決同一行程內不同執行緒間同步,對于分布式專案跨進城執行緒同步依賴于分布式鎖,synchronized鎖更多的意義是理解鎖的程序,
喜歡本文就【??推薦??】一下,激勵我持續創作,這個Github同樣精彩,收到您的star我會很激動,本文歸檔在專題博客,視頻講解在B站,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/461818.html
標籤:Java
上一篇:Golang的JWT權限校驗決議
下一篇:資料庫操作
