本文摘自《多線程編程實戰指南(核心篇)》java
單例模式所要實現的目標(效果)很是簡單:保持一個類有且僅有一個實例。出於性能的考慮,很多單例模式會採用延遲加載(Lazy Loading)的方式,即僅在須要用到相應實例的時候才建立實例。編程
單例模式 餓漢模式多線程
1 class SingleThreadSigleton{ 2 private static SingleThreadSigleton instance = new SingleThreadSigleton(); 3 4 SingleThreadSigleton(){ 5 } 6 7 public static SingleThreadSigleton getInstance() { 8 return instance; 9 } 10 }
單線程單例 懶漢模式ide
1 class SingleThreadSigleton{ 2 private static SingleThreadSigleton instance = null; 3 4 private SingleThreadSigleton(){ 5 } 6 7 public static SingleThreadSigleton getInstance(){ 8 if(null == instance){ 9 instance = new SingleThreadSigleton(); 10 } 11 return instance; 12 } 13 }
簡單加鎖實現的單例模式實現函數
1 class SingleThreadSigleton{ 2 private static SingleThreadSigleton instance = null; 3 4 private SingleThreadSigleton(){ 5 } 6 7 //靜態函數加synchronized至關於synchronized(xxx.class) xxx表示當前類 8 public static synchronized SingleThreadSigleton getInstance(){ 9 if(null == instance){ 10 instance = new SingleThreadSigleton(); 11 } 12 return instance; 13 } 14 }
基於雙重檢查鎖定的錯誤單例模式實現性能
1 class SingleThreadSigleton{ 2 private static SingleThreadSigleton instance = null; 3 4 private SingleThreadSigleton(){ 5 } 6 7 public static SingleThreadSigleton getInstance(){ 8 if(null == instance){ 9 synchronized (SingleThreadSigleton.class) { 10 if(null == instance) { 11 instance = new SingleThreadSigleton();//操做1 12 } 13 } 14 } 15 return instance; 16 } 17 }
由於須要考慮到重排序的因素,操做1能夠分解爲一下僞代碼所示的幾個獨立子操做flex
objRef = allocate(SingleThreadSigleton.class);//分配空間 invokeConstructor(objRef);//初始化objRef引用的對象 instance = objRef;//將對象引用寫入共享變量
根據重排序規則2和規則1:臨界區內的操做能夠在臨界區內被重排序。所以上述操做可能被重排序爲:子操做① -> 子操做③ -> 子操做②,這就可能致使程序出錯。spa
基於雙重檢查鎖定的正確單例模式實現線程
1 class SingleThreadSigleton{ 2 private volatile static SingleThreadSigleton instance = null; 3 4 private SingleThreadSigleton(){ 5 } 6 7 public static SingleThreadSigleton getInstance(){ 8 if(null == instance){ 9 synchronized (SingleThreadSigleton.class) { 10 if(null == instance) { 11 instance = new SingleThreadSigleton(); 12 } 13 } 14 } 15 return instance; 16 } 17 }
基於靜態內部類的單例模式實現code
1 class SingleThreadSigleton{ 2 3 private SingleThreadSigleton(){ 4 } 5 6 private static class InstanceHolder{ 7 final static SingleThreadSigleton INSTANCE = new SingleThreadSigleton(); 8 } 9 10 public static SingleThreadSigleton getInstance() { 11 return InstanceHolder.INSTANCE; 12 } 13 }
基於枚舉類型的單例模式實現
1 class EnumBasedSingletonExample{ 2 public static void main(String[] args) { 3 new Thread(new Runnable() { 4 @Override 5 public void run() { 6 SingleThreadSigleton.INSTANCE.someService(); 7 } 8 }).start(); 9 } 10 } 11 12 enum SingleThreadSigleton{ 13 INSTANCE; 14 SingleThreadSigleton(){ 15 } 16 public void someService(){ 17 //doSomething 18 } 19 }
單例模式防止反射、序列化、克隆的破壞
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.ObjectInputStream; 4 import java.io.ObjectOutputStream; 5 import java.io.Serializable; 6 import java.lang.reflect.Constructor; 7 8 9 public class Main implements Serializable, Cloneable { 10 private static final long serialVersionUID = 6125990676610180062L; 11 private static Main main; 12 private static boolean isFristCreate = true; 13 private Main(){ 14 /*防止反射破壞單例*/ 15 if(isFristCreate){ 16 synchronized (Main.class) { 17 if(isFristCreate){ 18 isFristCreate = false; 19 } 20 } 21 }else{ 22 throw new RuntimeException("已經實例化一次, 不能再實例化"); 23 } 24 } 25 26 public static Main getInstance(){ 27 if (main == null) { 28 synchronized (Main.class) { 29 if (main == null) { 30 main = new Main(); 31 } 32 } 33 } 34 return main; 35 } 36 /*防止克隆破壞單例*/ 37 @Override 38 protected Object clone() throws CloneNotSupportedException { 39 // TODO Auto-generated method stub 40 return main; 41 } 42 /*防止序列化破壞單例*/ 43 private Object readResolve() { 44 // TODO Auto-generated method stub 45 return main; 46 } 47 48 49 public static void main(String[] args) throws Exception{ 50 Main main = Main.getInstance(); 51 System.out.println("singleton的hashCode:"+main.hashCode()); 52 //經過克隆獲取 53 Main clob = (Main) Main.getInstance().clone(); 54 System.out.println("clob的hashCode:"+clob.hashCode()); 55 //經過序列化,反序列化獲取 56 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 57 ObjectOutputStream oos = new ObjectOutputStream(bos); 58 oos.writeObject(Main.getInstance()); 59 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 60 ObjectInputStream ois = new ObjectInputStream(bis); 61 Main serialize = (Main) ois.readObject(); 62 if (ois != null) ois.close(); 63 if (bis != null) bis.close(); 64 if (oos != null) oos.close(); 65 if (bos != null) bos.close(); 66 System.out.println("serialize的hashCode:"+serialize.hashCode()); 67 //經過反射獲取 68 Constructor<Main> constructor = Main.class.getDeclaredConstructor(); 69 constructor.setAccessible(true); 70 Main reflex = constructor.newInstance(); 71 System.out.println("reflex的hashCode:"+reflex.hashCode()); 72 } 73 }