標籤:java 單例
前言:Java的單例經常用到,今天發現自己有一點新的認識。
懶漢式單例
package com.mwq.singleton;public class Singleton1 { private Singleton1() { } private static Singleton1 single = null; public static Singleton1 getInstance() { if (single == null) { return new Singleton1(); } return single; } public String sayHello() { return "hello singleton1" + this; }}
這種方式是在第一次使用的時候進行一次單例的執行個體化,我以前也習慣用這種方式,卻不曾想這是線程不安全的,後面會寫執行個體證明。對於private static Singleton1 single = null; 為什麼沒有加final關鍵字,因為這種懶漢式寫法與final無關!
餓漢式單例
package com.mwq.singleton;public class Singleton2 { private Singleton2() { } private static final Singleton2 single = new Singleton2(); public static Singleton2 getInstance() { return single; } public String sayHello() { return "hello singleton2" + this; }}
這種方式在類建立的同時就進行了執行個體化,私人構造器僅僅被調用一次,這就保證它是安全的。
枚舉式單例
package com.mwq.singleton;public enum Singleton3 { INSTANCE; public String sayHello() { return "hello singleton3" + this; }}
寫法更快捷,我之前也未曾知道。
無償地提供了序列化機制,絕對防止多次執行個體化,即使在面對複雜的序列化或者反射攻擊的時候,無疑是最佳的singleton實現方式。—–effective Java一書
對於前面兩種是有可能被藉助setAcceessible() 方法進行反射攻擊的,但是我沒有找到怎麼避免?????
論證
package com.mwq.singleton;public class Test extends Thread{ public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(new Test()).start(); } } @Override public void run() { System.out.println(Singleton1.getInstance().sayHello()); System.out.println(Singleton2.getInstance().sayHello()); System.out.println(Singleton3.INSTANCE.sayHello()); System.out.println(); }}
通過以上的方法進行測試,得出如下內容:
hello [email protected]1b1aa65hello [email protected]1125127hello singleton3INSTANCEhello singleton1com.mwq.singleton.Singleton1@bb7465hello [email protected]2a5330hello [email protected]1125127hello singleton3INSTANCEhello [email protected]1125127hello singleton3INSTANCE
可以看出來懶漢式單例的確是不安全的,會建立多次執行個體,第二種和第三種是安全的。
總結:本文參考了JAVA設計模式之單例模式部落格,以及《effective Java 中文版》一書。
java:單例的理解