Java-多線程與單例

最近在公司寫需求時遇到了多線程與單例一同出現的狀況。安全

這個時候想到的就是線程安全以及單例的定義了,雖然單例指的是在內存中它只有一份,可是並非說就是線程安全的。多線程

因此,我當時就到網上找了關於多線程下單例的線程安全問題的資料,而後就知道以下博客:高併發下線程安全的單例模式(最全最經典)併發

其中,博主最推薦的寫做方式以下:高併發

爲了達到線程安全,又能提升代碼執行效率,這裏能夠採用DCL(Double Check Locking)的雙檢查鎖機制來完成

public class MySingleton {  
      
    //使用volatile關鍵字保其可見性  
    volatile private static MySingleton instance = null;  
      
    private MySingleton(){}  
       
    public static MySingleton getInstance() {  
        try {    
            if(instance != null){//懶漢式   
                  
            }else{  
                //建立實例以前可能會有一些準備性的耗時工做   
                Thread.sleep(300);  
                synchronized (MySingleton.class) {  
                    if(instance == null){//二次檢查  
                        instance = new MySingleton();  
                    }  
                }  
            }   
        } catch (InterruptedException e) {   
            e.printStackTrace();  
        }  
        return instance;  
    }  
} 

看了看內容確實是這個道理,而後就把這段代碼拿來使用了。而後在實際測試中發現,其並無保證線程安全的問題。測試

以後在同事的指點下發現,其實上文一段的線程安全僅僅只是在未實例化單例的前提下,以線程安全的方式實例化單例,使之在高併發多線程的環境下有且僅被new過一次。spa

也就是說,在單例被實例化以後,這段代碼是並無什麼做用的。.net

單例被實例化以後,instance != null一直成立,使getInstance()每次都是return instance。因此,多線程都能拿到指向同一個實例的引用。線程

因此即便是使用了這種雙檢查鎖機制的代碼,依然要對後面要使用到的公用方法作同步,以避免出現問題。code

而對公用方法作同步的操做也分兩種狀況。一種是公用方法裏只有局部變量,那麼此時不作同步也是能夠的,由於局部變量只會存在於相應的線程內存裏,並不會被其它線程所影響。另一種是含有成員變量,若是成員變量只有讀的操做,那不一樣步也能夠;若是成員變量涉及讀寫操做,那麼就要對相應的方法進行同步了。對象

局部變量不會受多線程影響
成員變量會受到多線程影響

多個線程應該是調用的同一個對象的同一個方法:
若是方法裏無成員變量,那麼不受任何影響
若是方法裏有成員變量,只有讀操做,不受影響
                      存在寫操做,考慮多線程影響值

 

來源:關於多個線程同時調用單例模式的對象,該對象中方法的局部變量是否會受多個線程的影響

相關文章
相關標籤/搜索