單例模式 → 破壞 → 阻止破壞

單例常用實(shí)現(xiàn)

  • 懶漢 線程不安全
  • 餓漢 基于static 線程安全
    a. 靜態(tài)成員變量
    b. 靜態(tài)塊兒
    c. 靜態(tài)內(nèi)部類
  • 枚舉:基于static 線程安全

  • a. AtomicReference CAS樂(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 排他鎖
  1. ThreadLocal 線程安全 單例有點(diǎn)牽強(qiáng)

破壞單例: 反射缩滨、序列化

  1. 反射
    原理:通過(guò)反射獲取默認(rèn)構(gòu)造函數(shù)實(shí)例化
  2. 反序列化
    原理:根據(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
    

阻止破壞單例:

  1. 針對(duì)反射的情況:
    構(gòu)造函數(shù)中增加標(biāo)志位,使構(gòu)造函數(shù)僅能被調(diào)用一次
  2. 針對(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]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碴犬,一起剝皮案震驚了整個(gè)濱河市絮宁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌服协,老刑警劉巖绍昂,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異偿荷,居然都是意外死亡窘游,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門跳纳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)忍饰,“玉大人,你說(shuō)我怎么就攤上這事棒旗〈” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵铣揉,是天一觀的道長(zhǎng)饶深。 經(jīng)常有香客問(wèn)我,道長(zhǎng)逛拱,這世上最難降的妖魔是什么敌厘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮朽合,結(jié)果婚禮上俱两,老公的妹妹穿的比我還像新娘。我一直安慰自己曹步,他們只是感情好宪彩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著讲婚,像睡著了一般尿孔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上筹麸,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天活合,我揣著相機(jī)與錄音,去河邊找鬼物赶。 笑死白指,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酵紫。 我是一名探鬼主播告嘲,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奖地!你這毒婦竟也來(lái)了状蜗?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鹉动,失蹤者是張志新(化名)和其女友劉穎轧坎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體泽示,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缸血,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了械筛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捎泻。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖埋哟,靈堂內(nèi)的尸體忽然破棺而出笆豁,到底是詐尸還是另有隱情郎汪,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布闯狱,位于F島的核電站煞赢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哄孤。R本人自食惡果不足惜照筑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘦陈。 院中可真熱鬧凝危,春花似錦、人聲如沸晨逝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捉貌。三九已至趴生,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昏翰,已是汗流浹背苍匆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棚菊,地道東北人浸踩。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像统求,于是被迫代替她去往敵國(guó)和親检碗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355