1. 程式人生 > >單例模式加鎖優化問題

單例模式加鎖優化問題

單例模式

單例模式特點:

  • 只有一個例項
  • 私有建構函式

單例模式應用場景:

  • 具有資源管理器的功能的應用,如印表機、執行緒池、快取、顯示卡驅動等等
  • 像我這初學的渣渣程式媛,在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);
}
    ....
}