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過一次。

也就是說,在單例被實例化之后,這段代碼是並沒有什么作用的。

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

所以即使是使用了這種雙檢查鎖機制的代碼,依然要對后面要使用到的公用方法做同步,以免出現問題。

而對公用方法做同步的操作也分兩種情況。一種是公用方法里只有局部變量,那么此時不做同步也是可以的,因為局部變量只會存在於相應的線程內存里,並不會被其它線程所影響。另外一種是含有成員變量,如果成員變量只有讀的操作,那不同步也可以;如果成員變量涉及讀寫操作,那么就要對相應的方法進行同步了。

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

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

 

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

 


免責聲明!

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



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