單例常用實(shí)現(xiàn)
- 懶漢
線程不安全
- 餓漢
基于static
線程安全
a. 靜態(tài)成員變量
b. 靜態(tài)塊兒
c. 靜態(tài)內(nèi)部類 - 枚舉:
基于static
線程安全
- 鎖
a. AtomicReferenceCAS樂(lè)觀鎖
優(yōu)點(diǎn):不需要使用傳統(tǒng)的鎖機(jī)制來(lái)保證線程安全忽舟,CAS是一種基于忙等待的算法囤躁,依賴底層硬件的實(shí)現(xiàn)友存,相對(duì)于鎖它沒(méi)有線程切換和阻塞的額外消耗笑窜,可以支持較大的并行度墨微。
缺點(diǎn):如果忙等待一直執(zhí)行不成功(一直在死循環(huán)中),會(huì)對(duì)CPU造成較大的執(zhí)行開(kāi)銷。
b. synchronized排他鎖
- ThreadLocal
線程安全
單例有點(diǎn)牽強(qiáng)
破壞單例: 反射缩滨、序列化
- 反射
原理:通過(guò)反射
獲取默認(rèn)構(gòu)造函數(shù)
實(shí)例化 - 反序列化
原理:根據(jù) Object 構(gòu)造函數(shù)反射生成。
步驟:- readObject() - readObject0(false) - readOrdinaryObject() // 關(guān)鍵方法 obj = desc.isInstantiable() ? desc.newInstance() : null; - newInstance() Object ob = in.readObject(); // 反序列化為 Object Target target = (Target) ob; // 強(qiáng)轉(zhuǎn)為目標(biāo)對(duì)象 Target
阻止破壞單例:
- 針對(duì)反射的情況:
構(gòu)造函數(shù)中增加標(biāo)志位,使構(gòu)造函數(shù)僅能被調(diào)用一次 - 針對(duì)反序列化的情況:
在單例類中實(shí)現(xiàn)readResolve()
方法脉漏。參考 readOrdinaryObject() 實(shí)現(xiàn)苞冯。
多種單例模式、破壞單例模式侧巨、組織破壞單例模式
public class ModeSingleton {
/**
* 通過(guò)反射舅锄,破壞單例模式
*/
static void destroySingletonByReflect() throws Exception {
SingletonOfHungary singleton = SingletonOfHungary.getInstance();
SingletonOfHungary newInstance;
Class<SingletonOfHungary> clazz = SingletonOfHungary.class;
// 獲取默認(rèn)構(gòu)造函數(shù)
Constructor<SingletonOfHungary> declaredConstructor = clazz.getDeclaredConstructor();
// 默認(rèn)構(gòu)造函數(shù)可訪問(wèn)
declaredConstructor.setAccessible(true);
// 創(chuàng)建對(duì)象
newInstance = declaredConstructor.newInstance();
System.out.println("singleton.hashCode: " + singleton.hashCode());
System.out.println("newInstance.hashCode: " + newInstance.hashCode());
}
/**
* 通過(guò)反序列化,破壞單例模式
*/
static void destroySingletonByDeSerialize() throws Exception {
SingletonOfHungary singleton = SingletonOfHungary.getInstance();
SingletonOfHungary newInstance;
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tmp"));
out.writeObject(singleton);
File file = new File("tmp");
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
//調(diào)用readObject()反序列化
newInstance = (SingletonOfHungary) in.readObject();
System.out.println("singleton.hashCode: " + singleton.hashCode());
System.out.println("newInstance.hashCode: " + newInstance.hashCode());
}
/**
* 阻止 反射破壞單例司忱。加構(gòu)造函數(shù)標(biāo)志位
*/
static void stopReflectDestroy() throws Exception {
SingletonOfInnerStatic singleton = SingletonOfInnerStatic.getInstance();
SingletonOfInnerStatic newInstance;
Class<SingletonOfInnerStatic> clazz = SingletonOfInnerStatic.class;
// 獲取默認(rèn)構(gòu)造函數(shù)
Constructor<SingletonOfInnerStatic> declaredConstructor = clazz.getDeclaredConstructor();
// 默認(rèn)構(gòu)造函數(shù)可訪問(wèn)
declaredConstructor.setAccessible(true);
// 創(chuàng)建對(duì)象
newInstance = declaredConstructor.newInstance();
System.out.println("singleton.hashCode: " + singleton.hashCode());
System.out.println("newInstance.hashCode: " + newInstance.hashCode());
}
/**
* 阻止 反序列化破壞單例巧娱。實(shí)現(xiàn) readResolve()
*/
static void stopDeSerializeDestroy() throws Exception{
SingletonOfInnerStatic singleton = SingletonOfInnerStatic.getInstance();
SingletonOfInnerStatic newInstance;
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tmp"));
out.writeObject(singleton);
File file = new File("tmp");
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
//調(diào)用readObject()反序列化
newInstance = (SingletonOfInnerStatic) in.readObject();
System.out.println("singleton.hashCode: " + singleton.hashCode());
System.out.println("newInstance.hashCode: " + newInstance.hashCode());
}
public static void main(String[] args) throws Exception {
System.out.println("反射,破壞單例模式:");
destroySingletonByReflect();
System.out.println("反序列化烘贴,破壞單例模式:");
destroySingletonByDeSerialize();
System.out.println("阻止 反射破壞單例:");
stopReflectDestroy();
System.out.println("阻止 反序列化破壞單例");
stopDeSerializeDestroy();
}
}
/**
* 懶漢 延遲初始化 - 不安全
*/
class SingletonOfLazy {
private static SingletonOfLazy instance;
private SingletonOfLazy() {
}
public static SingletonOfLazy getInstance() {
if (instance == null) {
instance = new SingletonOfLazy();
}
return instance;
}
}
/**
* 餓漢.靜態(tài)成員變量 類加載時(shí)初始化 - 線程安全
*/
class SingletonOfHungary implements Serializable {
private static SingletonOfHungary instance = new SingletonOfHungary();
private SingletonOfHungary() {
}
public static SingletonOfHungary getInstance() {
return instance;
}
}
/**
* 餓漢.靜態(tài)塊初始化靜態(tài)成員變量 類加載時(shí)初始化 - 線程安全
*/
class SingletonOfInnerStatic implements Serializable{
private static SingletonOfInnerStatic instance;
//申明一個(gè)標(biāo)志位禁添,用于標(biāo)志構(gòu)造函數(shù)是否被調(diào)用過(guò)
private static boolean alreadyExist;
static {
instance = new SingletonOfInnerStatic();
alreadyExist = true;
}
private SingletonOfInnerStatic() {
if (alreadyExist) {
System.out.println("單例模式不能破壞,已存在此單例桨踪!");
}
}
public static SingletonOfInnerStatic getInstance() {
return instance;
}
public Object readResolve() {
return instance;
}
}
/**
* 餓漢.靜態(tài)內(nèi)部類 類加載時(shí)初始化 - 線程安全
*/
class SingletonOfInnerClass {
private SingletonOfInnerClass() {
}
private static class SingletonHolder {
private static final SingletonOfInnerClass INSTANCE = new SingletonOfInnerClass();
}
public static SingletonOfInnerClass getInstance() {
return SingletonHolder.INSTANCE;
}
}
/**
* 枚舉.枚舉類的成員變量均為static 在靜態(tài)代碼塊中實(shí)例化 - 線程安全
*/
enum SingletonOfEnum {
INSTANCE;
}
/**
* 樂(lè)觀鎖 - 線程安全
*/
class SingletonOfCAS {
public static final AtomicReference<SingletonOfCAS> INSTANCE = new AtomicReference<>();
private SingletonOfCAS() {
}
public static SingletonOfCAS getInstance() {
for (; ; ) {
SingletonOfCAS singleton = INSTANCE.get();
if (null != singleton) {
return singleton;
}
singleton = new SingletonOfCAS();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}
/**
* ThreadLocal - 線程安全
* ThreadLocal是線程隔離的老翘,會(huì)為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突锻离。
* 對(duì)于多線程資源共享的問(wèn)題铺峭,同步機(jī)制(synchronized)采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式汽纠。
*/
class SingletonOfThreadLocal {
private SingletonOfThreadLocal() {
}
private static final ThreadLocal<SingletonOfThreadLocal> INSTANCE = ThreadLocal.withInitial(SingletonOfThreadLocal::new);
public static SingletonOfThreadLocal getInstance() {
return INSTANCE.get();
}
}
測(cè)試結(jié)果:
反射卫键,破壞單例模式:
singleton.hashCode: 1163157884
newInstance.hashCode: 1956725890
反序列化,破壞單例模式:
singleton.hashCode: 1163157884
newInstance.hashCode: 325040804
阻止 反射破壞單例:
單例模式不能破壞虱朵,已存在此單例莉炉!
singleton.hashCode: 1173230247
newInstance.hashCode: 856419764
阻止 反序列化破壞單例
singleton.hashCode: 1173230247
newInstance.hashCode: 1173230247
推薦 設(shè)計(jì)模式——單例模式的破壞 很詳細(xì),參考了[抱拳.jpg]