單例模式中可能存在的一些問題(線程安全問題)


單例的設計模式中,一些代碼的寫法會存在線程安全的問題,舉例如下:

(1)單例模式的懶漢式[線程不安全,不可用]

    public class Singleton {  
      
        private static Singleton instance=null;  
          
        private Singleton() {};  
          
        public static Singleton getInstance(){  
              
            if(instance==null){  
                instance=new Singleton();  
            }  
            return instance;  
        }  
    }  

這種方式是在調用getInstance方法的時候才創建對象的,所以它就被稱為懶漢模式。

這是存在線程安全問題的,那具體是存在怎樣的線程安全問題?怎樣導致這種問題的?好,我們來說一下什么情況下這種寫法會有問題。在運行過程中可能存在這么一種情況:多個線程去調用getInstance方法來獲取Singleton的實例,那么就有可能發生這樣一種情況,當第一個線程在執行if(instance==null)時,此時instance是為null的進入語句。在還沒有執行instance=new Singleton()時(此時instance是為null的)第二個線程也進入了if(instance==null)這個語句,因為之前進入這個語句的線程中還沒有執行instance=new Singleton(),所以它會執行instance = new Singleton()來實例化Singleton對象,因為第二個線程也進入了if語句所以它會實例化Singleton對象。這樣就導致了實例化了兩個Singleton對象。所以單例模式的懶漢式是存在線程安全的,既然它存在問題,那么可能有解決辦法,於是就有下面加鎖這種寫法。

(2)懶漢式線程安全的[線程安全,效率低不推薦使用]

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

缺點:效率太低了,每個線程在想獲得類的實例的時候,執行getInstance()方法都要進行同步。而其實這個方法只執行一次實例化代碼就夠了,后面想獲得該實例,直接return就行了。方法進行同步效率太低要改進。

(3)單例模式懶漢式[線程不安全,不可用]

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

這種寫法也是不安全的,當一個線程還沒有實例化Singleton時另一個線程執行到if(instance == null)這個判斷時語句機會進入if語句,雖然加了鎖,但是等到第一個線程執行完instance=new Singleton()跳出這個鎖時,另一個進入if語句的線程同樣會實例化另外一個SIngleton對象。因為這種改進方法不可行。

(4)單例模式懶漢式[線程安全,可用]

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

 

(5)單例模式餓漢式[線程安全,可用]

public class Singleton1 {  
    private Singleton1() {}  
    private static final Singleton1 single = new Singleton1();  
    //靜態工廠方法   
    public static Singleton1 getInstance() {  
        return single;  
    }  
} 

 

餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以后不再改變,所以天生是線程安全的。

(6)單例模式的成員變量[線程不安全,不可用]

public class Singleton {  
    int i =0;
    private Singleton() {}  
    private static final Singleton1 single = new Singleton1();  
    //靜態工廠方法   
    public static Singleton1 getInstance() {  
        i++;        
        return single;  
    }  
}     

 

這種寫法也是不安全的,當一個線程還沒有執行到i++時另一個線程執行到int i=0,導致i=1而不是2,應改為局部變量寫法較好

總結:

以上就是單例模式中,會引發的線程安全問題了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM