首頁 > 軟體

Java十分鐘快速掌握單例模式

2022-03-16 19:00:58

前言

首先在Java中有23種設計模式:

建立型模式:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式

結構型模式:介面卡模式、裝飾者模式、代理模式、外觀模式、橋接模式、組合模式、享元模式

行為型模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、存取者模式、中介者模式、直譯器模式。

1、什麼是單例模式:

定義:

指一個類只有一個範例,且該類能自行建立這個範例的一種模式。可以避免因開啟多個工作管理員視窗而造成記憶體資源的浪費,或出現各個視窗顯示內容的不一致等錯誤。比如咱們電腦是不是隻能開啟一個工作管理員?對吧,這就是為了防止資源浪費和其他錯誤。

專案中一般可以通過單例模式來獲取同一個物件來呼叫工具方法,這樣的好處是節約記憶體資源,我沒有必要建立多個不同的物件,因為這樣消耗記憶體資源

簡而言之: 單例就是程式只有一個範例,該類負責建立自己的物件,同時要確保只有一個物件建立

單例模式的特點:

  • 構造器私有
  • 持有自己型別的屬性
  • 對外提供獲取範例的靜態方法

單例模式的結構圖:

2、單例模式的優缺點:

優點:

  • 減少了記憶體的開銷
  • 避免對資源的多重佔用
  • 設定全域性存取點,可以優化和共用資源的存取

缺點(參考自網際網路):

  • 一般沒有介面,擴充套件困難。如果要擴充套件,則除了修改原來的程式碼,沒有第二種途徑,違背開閉原則
  • 在並行測試中,單例模式不利於程式碼偵錯。在偵錯過程中,如果單例中的程式碼沒有執行完,也不能模擬生成一個新的物件
  • 單例模式的功能程式碼通常寫在一個類中,如果功能設計不合理,則很容易違背單一職責原則

看一張單例模式的思維導圖:

3、懶漢模式(比較常用)

懶漢模式特徵是延遲初始化,在呼叫方法獲取範例的時候才會範例化物件 執行緒不安全,嚴格意義上來說不是單例模式,優勢是在獲取範例才會建立物件因此更節省記憶體開銷

Demo:

public class SingLeton {

    //1、有自己型別的屬性
    private static SingLeton instance;

    //2、構造器私有化
    private SingLeton(){}

    //3、對外提供獲取範例的靜態方法
    public static SingLeton getInstance(){
        if (instance == null){
            instance = new SingLeton();
        }
        return instance;
    }

}

測試類:

public class Test {
    public static void main(String[] args) {

        //判斷是否產生的是同一個物件
        SingLeton s1 = SingLeton.getInstance();
        SingLeton s2 = SingLeton.getInstance();
        System.out.println(s1 == s2);
    }
}

輸出:

true

注意

關於懶漢模式執行緒非安全

現在知道懶漢模式的執行緒是非安全的,那麼就需要使用鎖(synchronized )來同步:

/**
 *   保證 instance 在所有執行緒中同步
 */
public class SingLeton2 {

        //1、有自己型別的屬性
        private static volatile SingLeton2 instance ;    
        
        //2、構造器私有化
        private SingLeton2() {
        }

        public static synchronized SingLeton2 getInstance() {
            //getInstance 方法前加同步
            if (instance == null) {
                instance = new SingLeton2();
            }
            return instance;
        }
    }

如果是寫多執行緒,則不要刪除上例程式碼中的關鍵字 volatile 和 synchronized,否則將存線上程非安全的問題。如果不刪除這兩個關鍵字就能保證執行緒安全,但是每次存取時都要同步,會影響效能,且消耗更多的資源,這是懶漢式單例的缺點。

4、餓漢模式【推薦使用】

餓漢模式執行緒安全,常用,但是容易產生垃圾物件,因為餓漢模式一開始載入類的時候就初始化 了範例

Demo:

/**
 *
 * 餓漢模式
 */
public class SingLeton {

    //持有自己型別的屬性   (和懶漢一樣)
    //由於static修飾,只在類載入的時候執行一次,類載入的時候就範例化物件
    private static SingLeton instance = new SingLeton();

    //構造器私有化,不能通過它建立物件
    private SingLeton(){};

    //對外提供獲取範例的靜態方法
    public static SingLeton getInstance(){
        return instance;
    }
}

測試類:

public class Test {
    public static void main(String[] args) {

        //判斷是否產生的是同一個物件
        SingLeton s1 = SingLeton.getInstance();
        SingLeton s2 = SingLeton.getInstance();
        System.out.println(s1 == s2);
    }
}

輸出:

true

懶漢模式和餓漢模式對比:

  • 懶漢模式延遲載入,非執行緒安全,餓漢模式執行緒安全
  • 懶漢模式剛執行不範例化物件,需要的時候才範例化物件,相當於來講更節省記憶體開銷
  • 餓漢模式只要執行都會載入類的時候就給你初始化了,就需要使用更大的記憶體

圖解:

5、單例模式的應用場景

  • 需要經常建立的一些類,使用單例可以降低系統的記憶體壓力
  • 這個類只要求生成一個物件的時候,比如每個人的名字
  • 類建立範例時佔用資源較多,或範例化耗時較長,且經常使用
  • 頻繁存取資料庫或檔案的物件
  • 類需要頻繁範例化,而建立的物件又頻繁被銷燬的時候,如多執行緒的執行緒池

6、單例模式的應用範例

這裡使用懶漢式單例模式模擬產生班級的班長 分析: 在每一個學期內,班級的班長只有一人,所以適合用單例模式實現

Person類:

/**
 * 使用懶漢模式
 */

public class Person {

    //保證instance在所有執行緒中同步
    private static volatile Person instance;

    private Person(){
        System.out.println("產生一個班長");
    }

    //加上synchronized鎖
    public static synchronized Person getInstance(){
        if(instance == null){
            instance = new Person();
        }else {
            System.out.println("錯誤資訊:已經有一個班長,不能再產生");
        }
        return instance;
    }

    public void getName(){
        System.out.println("我是班長:小強");
    }
}

測試類:

public class Test {
    public static void main(String[] args) {

        Person p1 = Person.getInstance();
        p1.getName(); //輸出班長名字

        Person p2 = Person.getInstance();
        p2.getName();

        if(p1 == p2){
            System.out.println("兩個班長是同一個人");
        }else {
            System.out.println("兩個班長是同一個人");

        }
    }
}

執行結果:

產生一個班長
我是班長:小強
錯誤資訊:已經有一個班長,不能再產生
我是班長:小強
兩個班長是同一個人

小結:

這個就是單例模式,當程式已經產生一個物件後,就不會產生一個新的物件,即使有多個物件也是同一個物件而已,在使用懶漢模式的時候需要注意執行緒安全問題,在平時更加推薦使用餓漢模式,也需要注意資源的佔用。

到此這篇關於Java十分鐘快速掌握單例模式的文章就介紹到這了,更多相關Java 單例模式內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com