單例模式加鎖優化問題
阿新 • • 發佈:2019-01-06
單例模式
單例模式特點:
- 只有一個例項
- 私有建構函式
單例模式應用場景:
- 具有資源管理器的功能的應用,如印表機、執行緒池、快取、顯示卡驅動等等
- 像我這初學的渣渣程式媛,在Android開發中用的最多的地方就是資料庫DAO層中~~~~
單例模式型別:
- 餓漢式、懶漢式、登記式
餓漢模式
優點:一開始就建立例項,執行緒安全
缺點:佔記憶體,耗資源
public class Singleton { private static Singleton uniqueInstance = new Singleton(); //建立私有的構造方法 private Singleton() { ... } //建立公有靜態例項 public static Singleton getInstance() { return uniqueInstance; }
懶漢模式
優點:呼叫例項靜態方法時,沒有建立例項,再建立;合理利用資源,減少資源浪費
缺點:可能會引起執行緒衝突,不安全
public class Singleton { private static Singleton uniqueInstance = null; //建立私有的構造方法 private Singleton() { ... } //建立公有靜態例項 public static Singleton getInstance() { if(uniqueInstance == null){//當沒有例項的時候,再建立例項 uniqueInstance = new Singleton(); } return uniqueInstance; }
優化1:為了解決執行緒衝突,加鎖。這樣只有當一個執行緒釋放鎖後,下一個執行緒才能得到鎖,進去。
public class Singleton { private static Singleton uniqueInstance = null; //建立私有的構造方法 private Singleton() { ... } //建立公有靜態例項,注意在例項方法前加了synchronized public synchronized static Singleton getInstance() { if(uniqueInstance == null){//當沒有例項的時候,再建立例項 uniqueInstance = new Singleton(); } return uniqueInstance; }
但是這樣每個進來的執行緒都加鎖後再判斷例項是否已經存在,然而加鎖的次數越多,程式碼執行效能越慢,所以為了減少不必要的加鎖次數,進行再次優化。
優化2:減少加鎖次數
public class Singleton {
private static Singleton uniqueInstance = null;
//建立私有的構造方法
private Singleton() {
...
}
//建立公有靜態例項,注意在例項方法前加了synchronized
public static Singleton getInstance() {
if (uniqueInstance == null) {
// 在判斷例項是否存在的時候,再加鎖
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
二次優化後,當例項已經存在的時候就直接返回例項,提高了程式碼執行效能,且執行緒安全。
登記式
登記式單例模式用的不多,它主要是對一組單例模式進行的維護,主要是在數量上的擴充套件
通過map我們把單例存進去,這樣在呼叫時,先判斷該單例是否已經建立,是的話直接返回,不是的話建立一個登記到map中,再返回。對於數量又分為固定數量和不固定數量的。下面採用的是不固定數量的方式,在getInstance方法中加上引數(string name)。然後通過子類繼承,重寫這個方法將name傳進去。讓我們看看程式碼吧。(引用http://blog.csdn.net/lanzhizhuxia/article/details/7922977)
public class Singleton3 { private static Map<String,Singleton3> map = new HashMap<String,Singleton3>(); static{ //類似餓漢模式,類載入就建立例項 Singleton3 single = new Singleton3(); map.put(single.getClass().getName(), single); } //protected型別的預設構造子 protected Singleton3(){} //靜態工廠方法,返還此類惟一的例項 public static Singleton3 getInstance(String name) { if(name == null) { name = Singleton3.class.getName(); } if(map.get(name) == null) { try { map.put(name, (Singleton3) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } .... }