用java簡單實現單例模式


java實現單例模式

單例模式是一種常用的設計模式,是23中設計模式中的一種。

設計模式:設計模式是一種思想,是一種編程思想,是前人經驗的累積。

單例模式概念:在做某個項目中,創建了一個類,那么這個類只能生成一個對象。

單例模式有兩種實現方式分別:餓漢式和懶漢式

一.餓漢式

餓漢式:顧名思義,可以理解成一個餓漢,只要一加載類的時候就會創建了對象,因為用了static修飾,static修飾的成員隨着類的加載而加載的

實現步驟:1:構造函數私有化

     2:提供一個靜態對象屬性用來接收對象

     3:創建一個靜態方法用來獲取對象實例

具體代碼如下:

//那么怎么讓這個類在整個項目中生成一個對象呢?使用單例模式
    //單例模式第一種:餓漢式
    //弊端:占用內存,如果我不想隨着類的加載而加載,想延遲加載創建對象?需要用到懶漢式
    //為什么叫餓漢式呢?一加載類的時候就創建了對象,因為用了static修飾,static修飾的成員隨着類的加載而加載
    //1.第一步:構造方法需要私有化
    //2.第二步:提供一個靜態對象屬性用來接收對象
    //3.第三步:提供一個靜態方法用來獲取對象
    //隨着類的加載就馬上創建了對象,很嘰餓
    public static Single s=new Single();
    //私有的只能在本類中使用
    private Single(){}
    public static Single getSingle(){
        return s;
    }

二.懶漢式

懶漢式:比較懶的加載,不會隨着類的加載而加載,而是在你調用創建對象實例的方法時才會創建對想

實現步驟:

第一步:構造方法需要私有化
第二步:提供一個靜態屬性
第三步:提供一個方法用來創建對象

代碼實現如 :

 //懶漢式:顧名思義,這個是比較的懶的,在我們加載類的時候沒有創建對象,而是在你調用了方法的時候才創建
    //第一步:構造方法需要私有化
    //第二步:提供一個靜態屬性
    //第三步:提供一個方法用來創建對象
    public static LazySingle lazySingle;
    private LazySingle(){}
    public static LazySingle getLazySingle(){
        //這里面需要創建對象
        //怎么解決?也就是說如何避免兩個不同的線程創建不同的對象?
        //判斷對象是否為空,為空進去創建,不為空就不能夠創建
        //需要使用同步把生成的對象的相關代碼鎖起來(同步代碼塊或者同步方法都可以)
        // synchronized(鎖對象) {}  LazySingle.class字節碼對象
        //LazySingle加載到內存中去會編譯成LazySingle.class文件,
        // 到JVM內存中,首先會加載到方法區,
        // 方法區中可能不止一個LazySingle.class文件,可能會有Dag.class,Cat.class...
        // 這樣方法區中會存在很多的字節碼文件,用面向對象的思維編寫它,專門用一個類稱呼它Class類
        //那么每一個字節碼文件可以看成是一個字節碼文件對象
//        Class<LazySingle> lazySingleClass = LazySingle.class;//Class類,Class類中的 LazySingle.class對象
        //還沒有很完善,因為使用同步代碼塊會存在開鎖和關鎖的一個步驟,會降低執行效率,損耗時間
        //而且不同的線程去訪問它的時候都要執行同步代碼塊,會降低執行效率,消耗時間
        //因為使用同步代碼塊會降低執行效率,消耗時間,為了避免減少使用同步代碼塊的一個次數
        //需要判斷如果對象為空的時候才進入同步代碼塊
        //假如沒有創建對象之前,兩個不同的線程同時進入,那么所創建的對象也不一樣
        // 就需要用同步代碼塊把生成對象的相關代碼鎖起來
        // 鎖對象使用類的字節碼對象 因為使用同步代碼塊會消耗時間
        // 為了避免減少使用同步代碼塊的次數,需要判斷對象為空的時候,才進入同步代碼塊
        //這里是進行了雙重檢查 兩個if判斷
        if(lazySingle==null) {//如果不等於就不要創建,等於null創建 有利於提升執行效率
            synchronized (LazySingle.class) {//鎖對象使用字節碼對象
                //如何避免兩個線程創建創建不同的對象
                //判斷對象是否為空
                //判斷對象是否為空,為空進去創建,不為空就不能夠創建
                if (lazySingle == null) {
                    lazySingle = new LazySingle();
                }
            }
        }
        return lazySingle;
    }
    public void eat(){
        System.out.println("大口吃飯");
    }

三.創建測試類進行測試

代碼如下:

 //餓漢式
        Single single = Single.getSingle();//創建兩個對象
        Single single1 = single.getSingle();
        //如果返回true代表兩個對象是同一個對象,反之則不是
        System.out.println(single==single1);//結果為true
        System.out.println(single);
        System.out.println(single1);
        //懶漢式
        LazySingle lazySingle = LazySingle.getLazySingle();
        LazySingle lazySingle1 = LazySingle.getLazySingle();
        //假如沒有創建對象之前,兩個不同的線程同時進入(發生的幾率很小),那么所創建的對象也會不一樣
        System.out.println(lazySingle==lazySingle1);//結果為true
        System.out.println(lazySingle);
        System.out.println(lazySingle1);

擴展:可以十一下把雙重檢查兩個if判斷去掉則會出現輸出結果flase

不同線程去訪問的時候,那么它們所創建的對象是不一樣的
原因是什么?因為調用這個方法才去創建對象,相當去有一個線程去訪問這個方法
為什么會出現false?不同線程去訪問對象的時候,創建的對象是不一樣的
圖解如下:

怎么解決?也就是說如何避免兩個不同的線程創建不同的對象?加一個if判斷,判斷lazySingle == null是否為空,等於空就進入下面的代碼,反正,則不進入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM