單例模式幾種寫法

本文摘自《多線程編程實戰指南(核心篇)》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 }
相關文章
相關標籤/搜索