相親網(wǎng)站怎么做企業(yè)線上培訓(xùn)平臺(tái)有哪些
單例模式是設(shè)計(jì)模式之一,能保證某個(gè)類在程序中只存在唯一一份實(shí)例,而不會(huì)創(chuàng)建出多個(gè)實(shí)例
單例模式的具體實(shí)現(xiàn)方法有很多,最常見(jiàn)的是 “餓漢” 和 “懶漢” 兩種。
餓漢模式
class Singlenton{private static Singlenton instance = new Singlenton();public static Singlenton getInstance(){return instance;}//在此類的外面無(wú)法調(diào)用構(gòu)造方法,無(wú)法創(chuàng)建實(shí)例private Singlenton(){}
}
懶漢模式
類加載的時(shí)候不創(chuàng)建實(shí)例,第一次使用的時(shí)候才創(chuàng)建實(shí)例
單線程版
class Singletonlazy{private static Singletonlazy instance = null;public static Singletonlazy getInstance(){if(instance==null){instance = new Singletonlazy();}return instance;}private Singletonlazy(){}
}
多線程版
相比單線程版,多線程版考慮了線程安全問(wèn)題
線程安全問(wèn)題發(fā)生在首次創(chuàng)建實(shí)例時(shí),可能多個(gè)線程同時(shí)調(diào)用getInstance方法,就可能導(dǎo)致創(chuàng)建了多個(gè)實(shí)例。
加上 synchronized 可以改善線程安全問(wèn)題
class Singletonlazy{private static Singletonlazy instance = null;private static Object locker = new Object();public static Singletonlazy getInstance(){synchronized (locker){if(instance==null){instance = new Singletonlazy();}}return instance;}private Singletonlazy(){}
}
多線程版優(yōu)化
上面的代碼雖然說(shuō)解決了線程安全問(wèn)題,但是只要調(diào)用了getInstance方法,就會(huì)觸發(fā)加鎖操作,產(chǎn)生阻塞,影響性能。
我們想要優(yōu)化,就要在加鎖之前判定一下是否需要加鎖。
外層的if(instance==null)是判斷實(shí)例有沒(méi)有創(chuàng)建
內(nèi)層的if(instance==null)進(jìn)一步判斷實(shí)例有沒(méi)有創(chuàng)建,因?yàn)樵谕鈱?if 和加鎖之間,切換了線程并創(chuàng)建了實(shí)例,此時(shí)切換到原來(lái)的線程如果沒(méi)有判斷,就會(huì)創(chuàng)建出多個(gè)實(shí)例。
但是光加了一個(gè)外層 if 還不夠,此時(shí)可能因?yàn)橹噶钪嘏判蛞鸬木€程安全問(wèn)題
instance = new Singletonlazy();分為三條指令
- 分配內(nèi)存空間
- 執(zhí)行構(gòu)造方法
- 內(nèi)存空間的地址賦值給引用變量
編譯器可能按照 1 2 3 的順序來(lái)執(zhí)行,也可能按照 1 3 2 的順序執(zhí)行
當(dāng)按照 1 3 2的順序執(zhí)行時(shí),由于 3 是把內(nèi)存空間的地址賦值給引用變量,所以此時(shí) instance現(xiàn)在不為 null 了,此時(shí)如果其他線程判斷外層 if 時(shí),由于instance不為null了,所以直接返回instance,但是此時(shí)instance指向沒(méi)有初始化,上面值全是0的內(nèi)存,此時(shí)getInstance到的就是個(gè)錯(cuò)誤的值,會(huì)引發(fā)一系列不可預(yù)期的情況。
此時(shí),我們用volatile 關(guān)鍵字告知編譯器此變量指令不可重排序即可解決。
class Singletonlazy{private static volatile Singletonlazy instance = null;private static Object locker = new Object();public static Singletonlazy getInstance(){if(instance==null){synchronized (locker){if(instance==null){instance = new Singletonlazy();}}}return instance;}private Singletonlazy(){}
}