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