1. 程式人生 > >多執行緒併發下的單例模式實現

多執行緒併發下的單例模式實現

本文講解:單例模式在多執行緒技術上的實現方式


1.1 天生執行緒安全的餓漢式單例

//餓漢式單例類(執行緒安全):在類初始化時,已經自行例項化
public class MySingleton {  
    private static MySingleton instance = new MySingleton();  

    private MySingleton(){}  

    public static MySingleton getInstance() {  
        return
instance; } }

1.2 懶漢式單例

  1. 懶漢式單例:在方法呼叫獲取例項時才建立例項。

1.2.1 執行緒不安全的懶漢式單例

public class MySingleton {  
    private static MySingleton instance = null;  

    private MySingleton(){}  

    public static MySingleton getInstance() {  
        if(instance == null){   
            instance = new
MySingleton(); } return instance; } }

1.2.2 執行緒安全的懶漢式單例

1. 同步方法實現

public class MySingleton {  
    private static MySingleton instance = null;  

    private MySingleton(){}  

    public static synchronized MySingleton getInstance() {  // 加synchronized 
        if(instance == null){   
            instance = new MySingleton();  
        }  
        return instance;  
    }  
} 

2. 同步程式碼塊實現:雙重檢查鎖定(Double Check Locking ,DCL)—推薦

public class MySingleton {  
    private static MySingleton instance = null;  

    private MySingleton(){}  

    public static MySingleton getInstance() {  
        if (instance == null) {    
            synchronized (MySingleton.class) {    
               if (instance == null) {    
                  instance = new MySingleton();   
               }    
            }    
        }    
        return instance;   
    }  
} 

1.3 使用靜態內部類實現單例模式

  1. 保證多執行緒併發下的執行緒安全性。
public class MySingleton {  

    private MySingleton(){}  

    //內部類:只在第一次使用時載入
    private static class MySingletonHandler{  
        private static MySingleton instance = new MySingleton();  
    }   

    public static MySingleton getInstance() {   
        return MySingletonHandler.instance;  
    }  
} 

1.4 序列化與反序列化的單例模式實現

  1. 上述1.3中靜態內部類的實現方式雖然保證了單例在多執行緒併發下的執行緒安全性,但是在遇到序列化物件時,預設的方式執行得到的結果就是多例的,程式碼如下。

    public class MySingleton implements Serializable {  
        private static final long serialVersionUID = 1L;  
    
        private MySingleton(){}  
    
        //內部類  
        private static class MySingletonHandler{  
            private static MySingleton instance = new MySingleton();  
        }   
    
        public static MySingleton getInstance() {   
            return MySingletonHandler.instance;  //序列化時,會得到多例
        }  
    } 
    
    // 測試
    public class Test{  
        public static void main(String[] args) throws {  
            MySingleton singleton = MySingleton.getInstance();  
    
            File file = new File("MySingleton.txt");  
    
            // 序列化
            FileOutputStream fos = new FileOutputStream(file);  
            ObjectOutputStream oos = new ObjectOutputStream(fos);  
            oos.writeObject(singleton);  
            fos.close();  
            oos.close();  
    
            // 反序列化  
            FileInputStream fis = new FileInputStream(file);  
            ObjectInputStream ois = new ObjectInputStream(fis);  
            MySingleton rSingleton = (MySingleton) ois.readObject();  
            fis.close();  
            ois.close();  
        }  
    } 
  2. 解決:在反序列化的過程中使用readResolve()方法

    public class MySingleton implements Serializable {  
        private static final long serialVersionUID = 1L;  
    
        private MySingleton(){}  
    
        //內部類  
        private static class MySingletonHandler{  
            private static MySingleton instance = new MySingleton();  
        }   
    
        public static MySingleton getInstance() {   
            return MySingletonHandler.instance;  
        }  
    
        protected Object readResolve() throws ObjectStreamException {  
            return MySingletonHandler.instance;   
        }  
    }  

1.5 使用static程式碼塊實現單例

public class MySingleton{  
    private static MySingleton instance = null;  

    //靜態程式碼塊
    static{  
        instance = new MySingleton();  
    }  

    private MySingleton(){}  

    public static MySingleton getInstance() {   
        return instance;  
    }   
}

1.6 使用enum列舉資料型別實現單例模式

  1. 列舉類的構造方法在類載入是被例項化
public class ClassFactory{   

    private enum MyEnumSingleton{  
        singletonFactory;  

        private MySingleton instance;  

        private MyEnumSingleton(){  //列舉類的構造方法在類載入是被例項化  
            instance = new MySingleton();  
        }  

        public MySingleton getInstance(){  
            return instance;  
        }  
    }   

    public static MySingleton getInstance(){  
        return MyEnumSingleton.singletonFactory.getInstance();  
    }  
}  

class MySingleton{//需要獲實現單例的類,比如資料庫連線Connection  
    public MySingleton(){}   
}