java的單例模式小知識點
單例模式
目的
為了讓一個類有且僅有一個實例
優點
-
只允許一個,節省空間
-
不用頻繁創建刪除,提高性能
缺點
- 不容易擴展
- 長期不使用會被系統當作垃圾回收,造成系統狀態的丟失
實現
要點
- 防止外界隨意的創建對象=》一個私有的構造函數
- 保證只有一個實例 =》在私有靜態屬性中進行聲明(餓漢創建,懶漢聲明)
- 提供這個實例 =》提供靜態的公有方法創建和獲取私有對象
程式碼
問題
//會不會報錯?
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()方法加鎖
使用場景
- 對系統內資源同意讀寫的,配置文件,如mysql的名字,資料庫名,帳號密碼
- 創建對象資源過多