單例模式是創建型模式之一。
單例模式顧名思義是單例的,也就是只有一個實例化對象,這都來源於它的私有化構造函數。
單例模式特點:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例
單例模式的應用場景:Windows的Task Manager(任務管理器);網站的計數器; 多線程的線程池的設計; Web應用的配置對象的讀取(由於配置文件是共享的資源)。
單例模式的五種實現方法:
在看實現方法之前,要先了解一些java的知識:1、初始化順序依次是:(靜態變量、靜態初始化塊)–>(普通變量、初始化塊)–> 構造器;如果有父類,則順序是:父類static方法 –> 子類static方法 –> 父類構造方法- -> 子類構造方法 。
2、靜態變量特點:static變量值在類加載的時候分配空間,以后創建類對象的時候不會重新分配,后面根據需要是可以再次賦值的。公共性,就是說,一個類的靜態成員,它是屬於大伙的,所有的類對象共享的,不像成員變量是自己的。
1、餓漢模式
public class Singleton { // 私有構造 private Singleton() {} private static Singleton instance = new Singleton(); // 靜態工廠方法,方法沒有同步塊,所以效率高。 public static Singleton1 getInstance() { return instance; } }
餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以后不再改變,所以天生是線程安全的。
2、懶漢模式
public class Singleton { private static Singleton instance; private Singleton (){} //使用的同步鎖,降低了效率,但是在多線程可以防止創建多個實例 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
餓漢就是類一旦加載,就把單例初始化完成,保證getInstance的時候,單例是已經存在的了,
而懶漢比較懶,只有當調用getInstance的時候,才回去初始化這個單例。
3、雙重檢測模式
public class Singleton { public static volatile Singleton singleton = null; private Singleton(){} public static Singleton getInstance(){ if(singleton == null){ synchronize (Singleton.class){ if( singleton == null ) { singleton = new Singleton(); } } return singleton; } }
當兩個線程執行完第一個 singleton == null 后等待鎖, 其中一個線程獲得鎖並進入synchronize后,實例化了,然后退出釋放鎖,
另外一個線程獲得鎖,進入又想實例化,會判斷是否進行實例化了,如果存在,就不進行實例化了。
4、靜態內部類
public class Singleton { // 靜態內部類LazyHolder private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
此方法既實現了線程安全,又避免了同步帶來的性能影響。
還有就是類似的靜態代碼塊實現:
public class Singleton{ // 私有構造 private Singleton() {} private static Singleton single = null; // 靜態代碼塊 static{ single = new Singleton(); } public static Singleton getInstance() { return single; } }
5、枚舉類
public class SingletonFactory { // 內部枚舉類 private enum EnmuSingleton{ Singleton; private Singleton singleton; //枚舉類的構造方法在類加載是被實例化 private EnmuSingleton(){ singleton = new Singleton(); } public Singleton getInstance(){ return singleton; } } public static Singleton getInstance() { return EnmuSingleton.Singleton.getInstance(); } } class Singleton{ public Singleton(){} }
下面是一個單例模式使用的demo 餓漢模式
public class TestSingleton { String name = null; private TestSingleton() { } private static TestSingleton instance = new TestSingleton(); public static TestSingleton getInstance() { return instance; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void print() { System.out.println("the name is " + name); } public static void main(String[] args) { // TODO 自動生成的方法存根 TestSingleton ts1 = TestSingleton.getInstance(); ts1.setName("12345"); TestSingleton ts2 = TestSingleton.getInstance(); ts2.setName("56789"); ts1.print(); ts2.print(); if(ts1 == ts2){ System.out.println("創建的是同一個實例"); }else{ System.out.println("創建的不是同一個實例"); } } }