第六章單例模式與多執行緒——立即載入“餓漢模式”與延遲載入“懶漢模式”
阿新 • • 發佈:2018-11-04
立即載入就是使用類的時候已經將物件建立完畢了,也稱為“餓漢模式”
package test01;
public class MyObject {
// 建立物件
private static MyObject object = new MyObject();
private MyObject(){
}
//用來返回例項物件,因為此方法沒有同步,因此出現非執行緒安全問題
public static MyObject getInstance() {
return object;
}
}
延遲載入是在呼叫get方法時例項才被建立,也稱為“懶漢模式”
延遲載入模式缺點:在多執行緒環境中,延遲載入模式根本不能實現保持單例的狀態
package test02; //懶漢模式的缺點 //2018-9-27by tiffany public class MyObject { private static MyObject object; private MyObject() { } // 在get方法中建立物件,不能實現保持單例的狀態 public static MyObject getInstance() { try { if(object != null) { }else { Thread.sleep(2000); object = new MyObject(); } }catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return object; } }
建立三個執行緒並進行呼叫,輸出結果:
延遲載入模式的解決方案:
(1)宣告synchronized關鍵字
package test02; //使用synchronized關鍵字解決延遲載入模式非單例問題 //2018-09-27 by Tiffany public class MyObject01 { private static MyObject01 object; private MyObject01() { } synchronized public static MyObject01 getInstance() { if(object != null) { }else { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } object = new MyObject01(); } return object; } }
輸出結果是同一個雜湊值,但此種方法執行效率十分低下,嘗試考慮使用同步程式碼塊
(2)嘗試同步程式碼塊
package test02;
//使用同步程式碼塊解決延遲載入模式非單例情況
//2017-09-27 by Tiffany
public class MyObject02 {
private static MyObject02 object;
private MyObject02() {
}
public static MyObject02 getInstance() {
synchronized(MyObject02.class) {
if(object != null) {
}else {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
object = new MyObject02();
}
}
return object;
}
}
此方法執行效率依然很低
(3)針對某些重要的程式碼進行單獨的同步
同步程式碼塊可以針對某些重要的程式碼進行單獨的同步,而其他的程式碼則不需要同步,這樣雖然效率提高了,但是在多執行緒的情況下依然無法解決同一個物件的問題
(4)使用DCL雙檢查鎖機制(用來實現多執行緒環境下的延遲載入單例設計模式)