單例設計模式是在軟件系統中採用必定的方法,保證某個類只能存在一個實例對象,而且該類只能有一個靜態方法來獲取該對象。java
注意下面各種實現方式中的測試代碼都同樣:須要注意導入的包路徑便可。設計模式
package com.yefengyu; import com.yefengyu.type2.Singleton; public class Client { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); } }
該方式是靜態常量實現的餓漢式(類加載的時候便建立了實例):安全
package com.yefengyu.type1; public class Singleton { //類內部實例化 private final static Singleton INSTANCE = new Singleton(); //構造器私有化,防止new對象 private Singleton() { } //對外提供公有方法調用 public static Singleton getInstance() { return INSTANCE; } }
一、類加載的時候實例化,防止多線程問題。多線程
二、沒有使用懶加載,類加載就產生對象,若是始終未使用則形成內存浪費。可是該對象只有一個,浪費空間也不是很大,可使用,編寫的時候很是簡單。測試
該方式是靜態代碼塊實現的餓漢式spa
package com.yefengyu.type2; public class Singleton { private final static Singleton INSTANCE; static { //使用靜態代碼塊生成對象 INSTANCE = new Singleton(); } //構造器私有化,防止new對象 private Singleton() { } //對外提供公有方法調用 public static Singleton getInstance() { return INSTANCE; } }
該方式和方式一的優缺點相似。線程
該方式是同步方法實現懶漢式(只有第一次使用的時候才建立實例)設計
package com.yefengyu.type3; public class Singleton { private static Singleton instance; //構造器私有化,防止new對象 private Singleton() { } //只有在第一次使用的時候構造實例對象,使用synchronized避免多線程問題 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
一、解決了線程不安全問題code
二、效率低下,每次調用該方法都要涉及鎖的操做。對象
三、不推薦使用。
問:java設計模式的單例模式,在懶漢式中一開始聲明的類的實例化對象爲何只用private static聲明,但沒有加final關鍵字?而在餓漢式中聲明實例是使用了private static final修飾?
答:若是是final非static成員,必須在構造器、代碼塊、或者直接定義賦值;若是是final static成員變量,必須直接賦值或者在靜態代碼塊中賦值。而在懶漢式中若是直接賦值就達不到延遲加載的效果。
該方式是同步代碼塊實現懶漢式。
package com.yefengyu.type4; public class Singleton { private static Singleton instance; //構造器私有化,防止new對象 private Singleton() { } //只有在第一次使用的時候構造實例對象,使用synchronized代碼塊和雙重判斷避免多線程問題,而且提供效率 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
一、解決了線程不安全問題
二、效率高,只有前面的少數線程可能會獲取鎖,只要實例被建立,後面的線程通常只需第一個if判斷就返回了對象。
三、推薦使用。
該方式是靜態內部類實現懶漢式。
package com.yefengyu.type5; public class Singleton { private static Singleton instance; //構造器私有化,防止new對象 private Singleton() { } //靜態內部類,在外部類加載的時候不會加載靜態內部類 private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { //只有在使用到靜態內部類的時候纔會加載,而且經過類加載機制保證在初始化的時候只有一個實例產生 return SingletonInstance.INSTANCE; } }
一、線程安全,使用類加載機制保證初始化時只有一個線程。
二、外部類裝載的時候靜態內部類不會裝載,只有使用的時候纔會裝載,所以達成了懶漢式的效果。
單例設計模式的使用場景?
一個對象便可完成全部的工做,無需大量建立對象消耗資源。好比一個長鏈接,創建起來就能夠不斷髮送數據,此時若是每來一個請求就創建一個鏈接,那麼資源會消耗殆盡。
多線程測試:針對懶漢式
測試代碼:
for (int i = 0; i < 1000; i++) { new Thread(() -> { Singleton.getInstance(); }).start(); }
在new實例的時候加上打印,如:
public static synchronized Singleton getInstance() { if (instance == null) { System.out.println("建立實例"); instance = new Singleton(); } return instance; }