單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。 這種模式涉及到一個單一的類,該類負責建立本身的對象,同時確保只有單個對象被建立。這個類提供了一種訪問其惟一的對象的方式,能夠直接訪問,不須要實例化該類的對象。編程
一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例(好比管理學院首頁頁面緩存)。設計模式
二、避免對資源的多重佔用(好比寫文件操做)。緩存
沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。安全
懶漢式:就是用的時候再進行實例化對象。bash
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
複製代碼
這種實現方式不支持多線程,由於沒有同步鎖,多線程下不能正常工做。多線程
public class Singleton {
private static Singleton instance;
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
複製代碼
能夠在多線程環境下使用,可是效率過低。併發
優勢:一個對象初始化一次,節省內存。性能
缺點:必須用synchronized來維持單例,沒效率。測試
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
複製代碼
由於它做爲靜態資源,因此在類裝載時就被實例化ui
優勢:沒有加鎖,執行效率會提升。
缺點:類加載時就初始化,浪費內存。
public class Singleton {
private static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
複製代碼
採用雙鎖機制,安全且在多線程狀況下能保持高性能。詳細瞭解請點擊:Java併發編程 -- 單例模式線程安全問題
public class Singleton {
private static Singleton instance;
private static class SingletonHandler{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHandler.INSTANCE;
}
}
複製代碼
這種方式能夠說是惡漢式的變通版,SingletonHandler沒有被主動使用的狀況下是不會實例化Singleton對象的,因此這樣作,既能達到lazy式的加載,又能保證線程安全。
public enum Singleton {
INSTANCE;
public void myMethod() {
System.out.println("enum instance test");
}
}
複製代碼
它不只能避免多線程同步問題,並且還自動支持序列化機制,防止反序列化從新建立新的對象,絕對防止屢次實例化。
測試:
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.INSTANCE;
singleton.myMethod();
}
}
複製代碼
enum instance test
複製代碼
不建議使用第 1 種和第 2 種懶漢方式,建議使用第 3 種餓漢方式。只有在要明確實現 lazy loading 效果時,纔會使用第 5 種登記方式。若是涉及到反序列化建立對象時,能夠嘗試使用第 6 種枚舉方式。