文章出處

簡介

單例模式使得一個類的實例是唯一的,外部對它的訪問都針對同一個對象。
單例模式的使用可以是業務上的原因,比如一個User對象需要全局唯一,或者是性能上的考慮,避免創建代價較高的對象反復實例化。

實現方式

  • 餓漢式:性能不是問題時,且對象一定需要被實例化,線程安全
public class User {
    private static final User ourInstance = new User();

    public static User getInstance() {
        return ourInstance;
    }

    private User() {
    }
}
  • 雙重鎖定
    線程安全,較高的性能,無需每次都加鎖
public class User {
    private static volatile User ourInstance;

    public static User getInstance() {
        if (ourInstance == null) {
            synchronized (User.class) {
                if (ourInstance == null) {
                    ourInstance = new User();
                }
            }
        }
        return ourInstance;
    }

    private User() {
    }
}
  • 靜態內部類
    僅在第一次調用getInstance()時,發生實例化,而且字段初始化語句是線程安全的。
public class User {
   
    public static User getInstance() {
        return Holder.ourInstance;
    }

    private static class Holder {
        private static User ourInstance = new User();
    }

    private User() {
    }
}
  • 單例集合
    可以使用一個HashMap等集合來維護需要的單例對象,初始化放在程序啟動時或其它合適的時機。此時可以根據對象的不同方面對它進行分類,而且最終得到同一個實例。
    此時使用到的類型本身無需是單例的,這種形式處理app中會用到的若干個全局對象時蠻合適。

  • 單例數據結構
    像android中就有一個下面的幫助類,它為目標類型T進行惰性初始化。

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

使用:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

好處就是對無法修改的目標類型進行單例化,好像也沒多大卵用。

  • 枚舉方式
    線程安全,性能可以,就是怪怪的。
public enum User{  
    INSTANCE;  
} 

補充

  • clone和單例是沖突的
  • 反射可以破壞單例,只要加一個靜態的flag來標識是否創建過對象就可以了,反射還得走構造函數。
  • 反序列化:增加方法readResolve():
public Object readResolve(){
   return getInstance();
}

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()