單例模式的線程安全問題


例會帶來什么問題?

如果多個線程同時調用這個實例,會有線程安全的問題

 

單例一般用在什么地方?

單例的目的是為了保證運行時只有唯一的一個實例,最常用的地方比如拿到數據庫的連接,或者Spring的中創建BeanFactory操作,而這些操作都是調用他們的方法來執行某個特定的動作。

 

首先先來認識下兩種模式:  惡漢式  懶漢式

 

public class MyFactory {
    
//    //餓漢式  立即創建
//    private static MyFactory instance = new MyFactory();
//    public static MyFactory getInstance(){
//        return instance;
//    }

    //懶漢式用到的時候在創建,不用就不創建(有線程安全問題)
    private static MyFactory instance = null;
    public static MyFactory getInstance(){
     instance = new MyFactory();return instance;
    }   
}

 

 

下面總結一下解決線程安全的幾種方式:

方法一:在MyFactory 中加入了一個私有靜態內部類instanceHolder ,對外提供的接口是 getInstance()方法,也就是只有在MyFactory.getInstance()的時候,instance對象才會被創建,,沒有使用同步。保證了只有一個實例,還同時具有了Lazy的特性

public class MyFactory {
        private static class instanceHolder {   
            public static MyFactory instance = new MyFactory();   
        }   
      
        public static MyFactory getInstance() {   
            return MyFactory.instanceHolder.instance;   
        }   
}

測試代碼

import static org.junit.Assert.*;
import org.junit.Test;
public class MyFactoryTest {
    @Test
    public void testGetResource() {
        MyFactory mf1 = MyFactory.getInstance();
        MyFactory mf2 = MyFactory.getInstance();
        System.out.println(mf1 != null);//true
        System.out.println(mf1 == mf2);//true
    }
}

方式二:(懶漢式)

這種方式也沒有使用同步,並且確保了調用static getInstance()方法時才創建MyFactory的引用,

  private static MyFactory instance = new MyFactory();
public static MyFactory getInstance() {   return instance; }

測試代碼:同方法一

 

方式三:使用synchronized 通常會鎖定整個方法的是比較耗費資源的,實際會產生多線程訪問問題的是這一句代碼instance = new MyFactory();

為了減少資源的消耗,只鎖這一句就行了, 兩個線程並發地進入第一次判斷instance是否為空的if 語句內部,一個線程獲得了鎖執行new操作,另一個線程被阻塞,

當第一個線程執行完畢之后,第二個線程如果直接進行new操作也是不安全的。為了避免第二次new操作,添加第二次條件判斷,既二次檢查

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

測試代碼 同方法一

 

 

 


免責聲明!

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



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