java的單例模式小知識點

單例模式

目的

為了讓一個類有且僅有一個實例

優點

  1. 只允許一個,節省空間

  2. 不用頻繁創建刪除,提高性能

缺點

  1. 不容易擴展
  2. 長期不使用會被系統當作垃圾回收,造成系統狀態的丟失

實現

要點

  1. 防止外界隨意的創建對象=》一個私有的構造函數
  2. 保證只有一個實例 =》在私有靜態屬性中進行聲明(餓漢創建,懶漢聲明)
  3. 提供這個實例 =》提供靜態的公有方法創建和獲取私有對象

程式碼

問題

//會不會報錯?
public class test {
    public static void main(String[] args) {
        Sun sun1=new Sun();
    }
}
class Sun{
    Sun sun=new Sun();//它會一直創建Sun對象,解決:用static修飾
}

//運行結果
//Exception in thread "main" java.lang.StackOverflowError
//	at com.imooc.Sun.<init>(test.java:10).....

為什麼會報StackOverflowError異常?

圖片解釋:
第4行開始在棧記憶體中聲明一個叫s的sun對象,並指向堆記憶體中地址為「0xA」的Sun對象,此時地址「OxA「的Sun對象中有一個實例化本類的屬性,所以它又指向地址”0xB” 的Sun對象,此時地址”0xB” 中有一個Sun類型的屬性……所以會一直創建Sun對象,出現棧溢出

餓漢式

//餓漢式
public class SingletonTwo {
    //私有構造函數
    private SingletonTwo(){ 
    }
    /**私有靜態屬性
    	為什麼加static,假設不加static,就不能保證只有一個實例,可能會出現上面的問題
    	為什麼加private,假設不加private,外界就可以用SingletonTwo.instance=null,把你對象置為空,有危險
    */
    private static SingletonTwo instance=new SingletonTwo();
	/**公共返回
		為什麼加static,不加static訪問該方法的話需要進行實例化,但是該類已經把構造方法私有化,沒辦法實例,所以只能用static通過「類名.方法名()」調用
    */
    public static SingletonTwo getInstance(){
        return instance;
    }
}

每次調用前就實例化好了,空間換時間,提前載入以後調用更快

懶漢式

//懶漢式
public class SingletonOne {
    private SingletonOne(){

    }
    private static SingletonOne instance=null;

    public static SingletonOne getSingletonInstance(){
        if (instance==null)//一定要判斷
            instance= new SingletonOne();
        return instance;
    }
}

只有每次調用的時候才會實例化,時間換空間,但是當多執行緒同時訪問這個方法時,會存在危險

比如有執行緒thread1和thread2,thread1第一次運行到第9行,滿足條件正準備向下執行時,thread2搶到了執行許可權,thread2直接調用getSingletonInstance方法創建了一個SingletonOne對象,thread2執行完後,thread1繼續剛才的執行,從第10行開始,最後又創建了一個SingletonOne對象,此時就不滿足只創建一個實例的條件了
 解決:給getSingletonInstance()方法加鎖

使用場景

  1. 對系統內資源同意讀寫的,配置文件,如mysql的名字,資料庫名,帳號密碼
  2. 創建對象資源過多