一、單例模式1、什么是單例模式采取一定的方法,使程序中的某個類只存在一個實例對象,且該類對外提供一個獲取該對象的方法(一般為靜態(tài)方法)。 2、單例模式分類(1)餓漢式(2種寫法,線程安全) (2)懶漢式(3種寫法) (3)雙重檢查(推薦使用) 3、餓漢式單例模式(靜態(tài)常量版)(1)步驟: package singleton.pattern.demo1; /** * 演示 餓漢式單例模式,靜態(tài)變量版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 餓漢式單例模式,靜態(tài)變量版 */ class Singleton { // 在類的內(nèi)部創(chuàng)建實例對象。使用靜態(tài)變量,只被加載一次。 private static Singleton singleton = new Singleton(); /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { return singleton; } } (3)優(yōu)缺點: (4)UML圖:
4、餓漢式單例模式(靜態(tài)代碼塊)(1)步驟: package singleton.pattern.demo2; /** * 演示 餓漢式單例模式,靜態(tài)代碼塊版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 餓漢式單例模式,靜態(tài)代碼塊版 */ class Singleton { // 在類的內(nèi)部聲明一個實例對象 private static Singleton singleton; static { // 在代碼塊中實例化一個對象,同樣只加載一次 singleton = new Singleton(); } /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { return singleton; } } (3)優(yōu)缺點同上例 餓漢式單例模式(靜態(tài)常量版) 5、懶漢式單例模式(線程不安全)(1)步驟: package singleton.pattern.demo3; /** * 演示 懶漢式單例模式,線程不安全版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 懶漢式單例模式,線程不安全版 */ class Singleton { // 在類的內(nèi)部聲明一個實例對象 private static Singleton singleton; /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象。 當(dāng)調(diào)用該方法時,才去檢查并創(chuàng)建一個實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { if (singleton == null) { singleton = new Singleton(); } return singleton; } } (3)優(yōu)缺點: 6、懶漢式單例模式(線程安全,同步方法)(1)步驟: package singleton.pattern.demo4; /** * 演示 懶漢式單例模式,線程安全,同步方法版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 懶漢式單例模式,線程安全,同步方法版 */ class Singleton { // 在類的內(nèi)部聲明一個實例對象 private static Singleton singleton; /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象,并給方法加個synchronized關(guān)鍵字,解決同步的問題。 * 當(dāng)調(diào)用該方法時,才去檢查并創(chuàng)建一個實例對象。 * * @return 實例對象 */ public static synchronized Singleton getSingleTon() { if (singleton == null) { singleton = new Singleton(); } return singleton; } } (3)優(yōu)缺點:
7、懶漢式單例模式(同步代碼塊方法,線程不一定安全)(1)步驟: package singleton.pattern.demo5; /** * 演示 懶漢式單例模式,線程不一定安全,同步代碼塊版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 懶漢式單例模式,線程不一定安全,同步代碼塊版 */ class Singleton { // 在類的內(nèi)部聲明一個實例對象 private static Singleton singleton; /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象,在方法內(nèi)部加個同步代碼塊。 當(dāng)調(diào)用該方法時,才去檢查并創(chuàng)建一個實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { if (singleton == null) { synchronized (Singleton.class) { singleton = new Singleton(); } } return singleton; } } (3)優(yōu)缺點:
8、雙重檢查(Double Check)(1)步驟: package singleton.pattern.demo6; /** * 演示 單例模式,雙重檢查版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 單例模式,雙重檢查版 */ class Singleton { // 在類的內(nèi)部聲明一個實例對象 private static volatile Singleton singleton; /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象,在方法內(nèi)部加個同步代碼塊,在代碼塊內(nèi)部增加一個檢查處理。 當(dāng)調(diào)用該方法時,才去檢查并創(chuàng)建一個實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } (3)優(yōu)缺點:
9、靜態(tài)內(nèi)部類(1)步驟: package singleton.pattern.demo7; /** * 演示 單例模式,靜態(tài)內(nèi)部類版 * */ public class Demo { public static void main(String[] args) { Singleton singleton1 = Singleton.getSingleTon(); Singleton singleton2 = Singleton.getSingleTon(); System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 單例模式,靜態(tài)內(nèi)部類版 */ class Singleton { /** * 構(gòu)造器私有化(防止通過new創(chuàng)建實例對象) */ private Singleton() { } /** * 靜態(tài)內(nèi)部類,在被調(diào)用的時候才會被加載,實現(xiàn)懶加載。 且內(nèi)部使用靜態(tài)常量實例化一個對象,保證了線程安全問題。 */ public static class SingleTonInstance { public static final Singleton INSTANCE = new Singleton(); } /** * 向外暴露一個靜態(tài)的公共方法用于獲取實例對象,在方法內(nèi)部加個同步代碼塊,在代碼塊內(nèi)部增加一個檢查處理。 當(dāng)調(diào)用該方法時,才去檢查并創(chuàng)建一個實例對象。 * * @return 實例對象 */ public static Singleton getSingleTon() { return SingleTonInstance.INSTANCE; // 調(diào)用靜態(tài)內(nèi)部類的靜態(tài)屬性 } } (3)優(yōu)缺點: (4)UML圖:
10、枚舉(1)步驟: package singleton.pattern; /** * 演示 單例模式,枚舉版 * */ public class Demo { public static void main(String[] args) { SingleTon singleton1 = SingleTon.INSTACNE; SingleTon singleton2 = SingleTon.INSTACNE; System.out.println(singleton1 == singleton2); // 由于獲取的為同一個對象,所以輸出為true } } /** * 單例模式,枚舉版 */ enum SingleTon { INSTACNE; public void show() { System.out.println("hello world"); } } (3)優(yōu)缺點:
11、JDK中的單例模式舉例(Runtime)(1)部分源碼 public class Runtime { private static Runtime currentRuntime = new Runtime(); /** * Returns the runtime object associated with the current Java application. * Most of the methods of class <code>Runtime</code> are instance * methods and must be invoked with respect to the current runtime object. * * @return the <code>Runtime</code> object associated with the current * Java application. */ public static Runtime getRuntime() { return currentRuntime; } /** Don't let anyone else instantiate this class */ private Runtime() {} } (2)可以看到上述代碼中采用的是 餓漢式單例模式(靜態(tài)變量版)。 12、單例模式使用注意(1)當(dāng)頻繁創(chuàng)建、銷毀某個對象時,可以采用單例模式。
|
|