1.synchronized優化方案
1.1 鎖消除
鎖消除即洗掉不必要的加鎖操作,虛擬機即時編輯器在運行時,對一些“代碼上要求同步,但是被檢測到不可能存在共享資料競爭”的鎖進行消除,
根據代碼逃逸技術,如果判斷到一段代碼中,堆上的資料不會逃逸出當前執行緒,那么可以認為這段代碼是執行緒安全的,不必要加鎖,
看下面這段程式:
public class SynchronizedTest {
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
for (int i = 0; i < 100000000; i++) {
test.append("abc", "def");
}
}
public void append(String str1, String str2) {
StringBuffer sb = new StringBuffer();
sb.append(str1).append(str2);
}
}
雖然StringBuffer的append是一個同步方法,但是這段程式中的StringBuffer屬于一個區域變數,并且不會從該方法中逃逸出去(即StringBuffer sb的參考沒有傳遞到該方法外,不可能被其他執行緒拿到該參考),所以其實這程序是執行緒安全的,可以將鎖消除,
1.2 鎖粗化
如果一系列的連續操作都對同一個物件反復加鎖和解鎖,甚至加鎖操作是出現在回圈體中的,那即使沒有出現執行緒競爭,頻繁地進行互斥同步操作也會導致不必要的性能損耗,
如果虛擬機檢測到有一串零碎的操作都是對同一物件的加鎖,將會把加鎖同步的范圍擴展(粗化)到整個操作序列的外部,
舉個例子:
public class StringBufferTest {
StringBuffer stringBuffer = new StringBuffer();
public void append(){
stringBuffer.append("a");
stringBuffer.append("b");
stringBuffer.append("c");
}
}
這里每次呼叫stringBuffer.append方法都需要加鎖和解鎖,如果虛擬機檢測到有一系列連串的對同一個物件加鎖和解鎖操作,就會將其合并成一次范圍更大的加鎖和解鎖操作,即在第一次append方法時進行加鎖,最后一次append方法結束后進行解鎖,
2.synchronized使用注意事項
-
sync加在靜態方法(static)時鎖的是類,比如 sync(A.class)
-
sync的鎖粒度應該盡量小,保證原子性即可
-
synchronized遇到例外時會自動釋放鎖,需要在catch塊中做處理
-
sync只能鎖住堆,不要鎖String(方法區-常量池)
-
sync是可重入鎖,在sync塊中呼叫sync方法自動獲得鎖
-
模擬死鎖
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/82613.html
標籤:其他
上一篇:Java 面試筆記之常考知識點 ThreadLocal 剖析
下一篇:多執行緒基礎知識
