单例模式的java实现
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
? ? ?前段時(shí)間買了幾本java相關(guān)的書,每天晚上回去看一兩個(gè)小時(shí),感受頗深.因此寫幾篇隨筆,作為讀書筆記,加深下個(gè)人理解,順便與大家分享下.因?yàn)樗接邢?文章中可能難免有不當(dāng)之處,希望各位多多指出,小弟在此謝過.? ? 單例模式(singleton)顧名思義,就是只有一個(gè)實(shí)例。
? ? 作為對象的創(chuàng)建模式, 單例模式確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。這個(gè)類稱為單例類。
? ? 在java語言中,單例模式的兩大好處:
? ? ? ? 1、對于頻繁使用的對象,使用單例模式,可以減少創(chuàng)建對象所花費(fèi)的時(shí)間,對于那些重量級對象而言,是非常可觀的系統(tǒng)開銷。
? ? ? ? ?2、由于new的操作次數(shù)減少,因此可以降低對內(nèi)存的使用頻率,減輕GC壓力,縮短GC停頓時(shí)間。
? ? 單例模式的三個(gè)要點(diǎn):? ? ?一是某個(gè)類只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
? ? ?一、首先我們來實(shí)現(xiàn)一個(gè)簡單的單例。
? ? ? ? 1)為了確保一個(gè)類只有一個(gè)實(shí)例,所以我們這里要把類的構(gòu)造方法使用private修飾。(注:使用private修飾構(gòu)造方法也不能確保該類不會(huì)在其他地方被初始化,使用反射可以做到,但是反射式特殊情況,這里不予考慮。 :) ?.)
? ? ? ? 2)類必須有一個(gè)static方法可以產(chǎn)生實(shí)例。
/*** 簡單的單例模式實(shí)現(xiàn)* @author shine*/ public class MySingleton {private MySingleton(){ //使用private修飾,避免在其他地方被實(shí)例化System.out.println("create MySingleton class");}private static MySingleton singleton=new MySingleton();public static MySingleton getInstance(){//static方法,提供自身實(shí)例return singleton;} } ?????? ? 測試代碼 public class MainTest {public static void main(String[] args) {MySingleton mySingleton=MySingleton.getInstance();} } ????? ?控制臺輸出:create MySingleton class?????
????????到現(xiàn)在,我們已經(jīng)自己實(shí)現(xiàn)了一個(gè)單例模式,這種單例模式很簡單,而且很可靠。
????? ? 但是假如我們遇到了這種情況:你只想調(diào)用該類的一個(gè)靜態(tài)方法,并不想拿到該類的實(shí)例,會(huì)發(fā)生什么情況?
/*** 簡單的單例模式實(shí)現(xiàn)* * @author shine*/ public class MySingleton {private MySingleton() { // 使用private修飾,避免在其他地方被實(shí)例化System.out.println("create MySingleton class");}private static MySingleton instance= new MySingleton();public static MySingleton getInstance() {// static方法,提供自身實(shí)例return instance;}public static void doSomeThing() { //模擬單例類扮演其他角色System.out.println("now is" + new Date());} }
????假如我們的MySingleton類在系統(tǒng)中還扮演其他角色,比如說輸出當(dāng)前時(shí)間等等。那么在我們調(diào)用這些方法的時(shí)候,我們的類實(shí)例就會(huì)被創(chuàng)建出來。因?yàn)槲覀兊膇nstance成員變量是被static修飾的,所以在JVM加載我們的單例類的時(shí)候,單例對象就會(huì)被建立出來。也就是說,在任何使用單例類的的地方都會(huì)初始化我們的單例變量,而無論我們是否需要一個(gè)實(shí)例。
? ? ? 測試如下
public class MainTest {public static void main(String[] args) {MySingleton.doSomeThing(); //我們只需調(diào)用方法,不需要實(shí)例} }
????????控制臺輸出如下:
????????create MySingleton class
????????now isWed Dec 12 22:32:03 CST 2012
? ? ? ?如果我們的單例類比較重量級,那么同樣在這里也是一筆多余的性能開銷。
? ? ? 二、為了解決這個(gè)問題,我們需要實(shí)現(xiàn)延遲加載機(jī)制.
????
/*** 單例模式(懶加載機(jī)制)* * @author shine* */ public class LazySingleton {private LazySingleton() {System.out.println("create LazySingleton class");}private static LazySingleton instance = null;public synchronized static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}public static void doSomeThing() {// 模擬單例類扮演其他角色System.out.println("now is" + new Date());} }?? ? 首先對于我們的靜態(tài)成員變量(也就是我們的實(shí)例)初始值賦予null.確保系統(tǒng)啟動(dòng)該類被加載的時(shí)候沒有額外的負(fù)擔(dān)。然后在我們的工廠方法getInstatnce()中,首先判斷單例是否已經(jīng)存在,如果存在則直接返回,否則就創(chuàng)建一個(gè)新的實(shí)例。?
? ? 這里需要注意的是,getInstatnce()必須是同步的,因?yàn)樵诙嗑€程環(huán)境下,當(dāng)線程1正在新建單例時(shí),完成賦值操作前。線程2可能正好判斷instance為null,也去執(zhí)行創(chuàng)建實(shí)例的操作,有可能導(dǎo)致多個(gè)實(shí)例被創(chuàng)建。所以同步關(guān)鍵字是必須的。
? ? 測試如下
public class MainTest {public static void main(String[] args) {System.out.println("test MySingleton doSomeThing");MySingleton.doSomeThing(); //我們只需調(diào)用方法,不需要實(shí)例System.out.println("test LazySingleton doSomeThing");LazySingleton.doSomeThing();//我們只需調(diào)用方法,不需要實(shí)例} } 控制臺輸出:
test MySingleton doSomeThing
create MySingleton class
now isWed Dec 12 22:49:54 CST 2012
test LazySingleton doSomeThing
now isWed Dec 12 22:49:54 CST 2012
? ? 通過這種方式,我們雖然實(shí)現(xiàn)了延遲加載的功能,但是和第一種方式比,它引入了同步關(guān)鍵字,所以多線程環(huán)境中,它的時(shí)間消耗要遠(yuǎn)遠(yuǎn)大于第一種單例模式。為了延遲加載反而降低了系統(tǒng)性能,是不是有點(diǎn)得不償失呢?我們再對其進(jìn)行改造:
三、無需同步的延遲加載,提高性能
/*** 單例模式,使用內(nèi)部類實(shí)現(xiàn)的延遲加載* @author shine**/ public class StaticSingleton {private StaticSingleton() {System.out.println("create StaticSingleton class");}public static class SingletonHolder {private static StaticSingleton instance = new StaticSingleton();}public static StaticSingleton getInstance() {return SingletonHolder.instance;} }
在這段代碼中,通過內(nèi)部類實(shí)現(xiàn)單例類的延遲加載。當(dāng)StaticSingleton被加載的時(shí)候,它的內(nèi)部類不會(huì)被初始化,只有在調(diào)用getInstance()方法的時(shí)候,才會(huì)加載內(nèi)部類,從而初始化instance實(shí)例。
? ?因?yàn)閷?shí)例的建立是在類加載的時(shí)候完成,所以天生對多線程友好。因此,這種方式兼?zhèn)湟陨蟽煞N方式的優(yōu)點(diǎn)。
注:本文部分內(nèi)容來自《java程序性能優(yōu)化》一書。轉(zhuǎn)載請注明出處。
以后會(huì)持續(xù)發(fā)表相關(guān)的讀書筆記,請關(guān)注。:) 謝謝。
轉(zhuǎn)載于:https://my.oschina.net/building/blog/95481
總結(jié)
以上是生活随笔為你收集整理的单例模式的java实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Rhel5.6下构建在线邮件服务系统并实
- 下一篇: 垃圾“程序是怎样练成的”——关于《C程序