單例模式的特徵
- 私有的構造函數
- 提供靜態變量
- 提供靜態的獲取實例方法
單例模式六種寫法
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 餓漢式
*/
public class Singleton {
private static Singleton sInstance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return sInstance;
}
}
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 懶漢式
*/
public class Singleton {
private static Singleton sInstance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (sInstance == null) {
sInstance = new Singleton();
}
return sInstance;
}
}
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 懶漢式(線程安全)
*/
public class Singleton {
private static Singleton sInstance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (sInstance == null) {
sInstance = new Singleton();
}
return sInstance;
}
}
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 雙重檢查鎖
*/
public class Singleton {
private static volatile Singleton sInstance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (sInstance == null) {
synchronized (Singleton.class) {
if (sInstance == null) {
sInstance = new Singleton();
}
}
}
return sInstance;
}
}
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 靜態內部類實現單例模式
*/
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
/**
* @author: lilinjie
* @date: 2019-08-27 13:37
* @description: 枚舉實現單例模式
*/
public enum Singleton {
INSTANCE;
public static Singleton getInstance() {
return INSTANCE;
}
}
// CAS操作實現單例
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();
public Singleton getInstance() {
for (; ; ) {
Singleton singleton = INSTANCE.get();
if (singleton != null) {
return singleton;
}
singleton = new Singleton();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}
單例模式注意點
- 反射可能會破壞單例模式,通過反射可以強制調用構造函數,生成對象實例,這裏構造函數內部可以加入判斷,如果對象實例已存在,則拋出異常,禁止再次調用。
- 反序列化可能會破壞單例,反序列還的過程中,會重新生成對象,這裏可以在單例類中定義一個readResolve()方法,內部返回已創建的實例,使其在反序列化的過程中調用該方法,仍然返回之前的實例。
- 克隆可能會破壞單例模式,通過重寫clone方法,返回已創建的實例