單例模式是一個老生常談的話題了,如何實現呢?我們這裏不再贅述,我們這裏梳理一下思路,看看設計一個單例模式需要考慮的問題。
1,延遲加載
new操作放在方法內部,不要作爲類的靜態成員變量暴露給調用者。
2,只實例化一次
實例化之前先判斷是否爲null。
3,線程安全
有多種思路:synchronized關鍵字,內部類等。
synchronized關鍵字其實就是加鎖,這是jvm給我們提供的一種線程安全機制。
內部類是使用到了jvm類加載機制,jvm能夠保證一個類在加載的時候是線程安全的。
4,規避反射調用
反射機制增強了java的動態性,但是也會帶來一些問題。比如我們這裏要討論的,反射機制破壞了單例模式,爲什麼呢?因爲反射機制可以繞過java類的訪問權限,調用java類的私有構造方法,生成類對象。
兵來將擋水來土掩。要解決這個問題,我們最常用的方式是拋異常。
private SomeClass() {
throw new IllegalStateException("禁止反射調用生成實例,因爲這樣會破壞我的單例模式!");
}
好了,只要掌握了這幾個要點,然後結合自己的業務場景,相信你也可以寫出自己的單例類了。
下面我們看一個實例:Logger實例。
我們在實際開發中,打印日誌都會這樣來寫:
private static final Logger logger = LoggerFactory.getLogger(Xxx.class);
Slf4j日誌框架在生成logger實例時,使用了單例模式,當然,還有其他設計模式,比如工廠模式和門面模式等。
我們看一下源碼,源碼在LoggerFactory.class中,最終調用方法getLoggerFactory(),該方法源碼如下:
}