------- android培訓、java培訓、期待與您交流! ----------
單例設計模式
第一部分:
1、設計模式的概念:
每一個模式描述了一個在我們周圍不斷重複發生的問題,以及該問題的解決方案的核心。這樣,你就能一次有一次地使用該方案而不必做重複勞動;而模式就是解決某一類問題最行之有效的方案;這是一個純粹偏思想的,在不斷的勞動的過程中總結出來的。2、設計模式的特點:
2.1、將某一類問題解決起來會變的更簡單;2.2、讓複雜的問題簡單化;
3、單例設計模式:
解決一個類在內存中存在一個對象;換句話說就是在一個類中只能有一個對象,不可能會出現第二個對象;4、單例設計模式的由來:
現在有兩個程序,分別是A程序和B程序,當A程序要操作一個文件的時候,這是就要new一個對象,當B文件也要操作一個文件的時候,同樣也要new一個新的對象,但是A和B操作的不是同一個對象,因此這時要保證對象的唯一性;
5、單例設計模式的思想:
5.1、爲了避免其他程序過多建立該類對象,先禁止其他程序建立該類對象;5.2、禁止其他的程序建立對象,由自己來建立對象;5.3、爲了讓其他程序可以訪問到該類對象,只好在本類中,自定義一個對象;5.4、爲了方便其他程序對自定義對象的訪問,可以對外提供一些訪問方式;6、單例設計模式的步驟:
6.1、將構造函數進行私有化;6.2、在類中創建一個本類對象;6.3、提供一個方法可以獲取到該對象;7、代碼表現:
<span style="font-size:18px;">class Single { private int num; public void setNum(int num) { this.num = num; } public int getNum() { return num; } // 將構造函數進行私有化; private Single(){} // 創建一個本類對象; private static Single s = new Single(); // 返回的是一個Single類型的對象; public static Single getInstance()//一個類類型的 { return s; } } class SingleDemo { public static void main(String[] args) { // 類名調用靜態方法 Single s1 = Single.getInstance(); Single s2 = Single.getInstance(); // Single s1 = new Single(); // Single s2 = new Single(); s1.setNum(30); System.out.println(s2.getNum()); // Single ss =Single.getInstance(); } } /* 打印的是30,說明s1 和s2 指向的是同一個對象 */</span><span style="font-size:24px;font-weight: bold;"> </span>
8、運行的結果:
設置的是s1的值是30,而打印的是s2的值也是30,由此可以s1和s2所指向的是同一個對象;
9、圖形展示:
10、單例設計模式應用:
對於事物該怎麼描述,還是怎麼描述,當需要將該事物的對象保證在內存中唯一性時,就加入單例設計模式思想即可;
舉例:
class Student { private int age;//要將屬性進行私有化 public void setAge(int age) { this.age = age; } public int getAge() { return age; } // 要求保證在內存中的唯一性,那麼就加上下面的三步 private Student(){} private static Student s = new Student(); public static Student getInstance() { return s; } } class SingleStudentDemo { public static void main(String[] args) { // 調用靜態方法; Student s1 = Student.getInstance(); Student s2 = Student.getInstance(); s1.setAge(34); System.out.println(s2.getAge()); } }
運行後的結果:
第二部分:
1、餓漢式
先初始化對象,開發一般會用餓漢式
2、餓漢式特點
2.1、Single類進內存,對象還沒有存在,就已經創建好了對象;2.1、安全,簡單;3.餓漢式代碼體現
<span style="font-size:14px;">//第一種,這個是先初始化對象 //稱爲:餓漢式 class Single { private Single(){} private static Single s = new Single(); public static Single getInstance() { return s; } }</span>
4、懶漢式
對象是方法被調用時,才初始化,也就做對象的延時加載;
5、延時加載
特點:Single類進內存,對象還沒有存在,只有調用了getInstance方法時,才建立對象;
6、懶漢式的特點
剛開始不建立對象,如果什麼時候需要,那麼就什麼時候建立對象;
7、懶漢式代碼體現
//第二種,對象是方法調用時,才初始化,也叫做對象的延時加載,稱爲懶漢式 class Single { private Single(){} private static Single s =null; public static Single getInstance() { if(s==null) { synchronized(Single.class) { if(s==null) s = new Single(); } } return s; } } class SingleDemo { public static void main(String[] args) { Single ss = Single.getInstance(); } }
8、懶漢式的缺陷
8.1、缺陷:
如果遇到多線程時,當A程序讀到getInstance的方法的時候,當cpu執行到s==null時,但是這時cpu切換到去處理B程序了,但是這時A程序就處於休息狀態,沒有執行程序,但是這時B程序同樣也進來了,判斷了s==null也是滿足條件的,現在A程序醒了,然後執行了s = new Single();創建了一個對象,這是B程序也醒了,又創建了一個對象;換句話說就是現在內存中的對象已經不唯一了,懶漢式在多線程訪問時會出現安全隱患;
8.2、措施:
在函數上加上一個鎖就是Synchronized,這時如果A程序進來之後,但是B程序就不可以進入程序了,A程序創建了對象之後,然後返回了,這時B程序判斷s已經不等於null,那麼就不再執行程序了。但是在這個鎖加載函數上面,每一個線程都要先進行判斷一下,效率比較低效;這時如何能夠既能可以保證對象的唯一性又能解決低效的問題?用雙重判斷來解決:判斷鎖的次數減少了;
9、面試
9.1、問:懶漢式和餓漢式有什麼不同?
答:懶漢式的特點在於實例的延時加載。9.2、問:懶漢式的延遲加載有沒有問題?
答:有,如果多線程訪問時,會出現安全問題。
9.3、問:出現了安全問題怎麼解決?
答:可以加同步來解決,而加同步的方式有兩種,同步代碼快和同步函數都行,但是稍微有些低效,用雙重判斷的形式可以解決效率的問題。
9.4、問:加同步的時候使用的鎖是哪一個?
答:該類所屬的字節碼文件對象。
第三部分
我的總結:
1、定義單例的時候建議使用餓漢式,因爲餓漢式不會出問題,簡單安全;2、使用單例延時加載的時候,保證對象的唯一性,以及用雙重判斷來提高效率;3、餓漢式的特點:對象先進行初始化;懶漢式的特點:對象後進行初始化;4、懶漢式如何在多線程訪問時解決安全隱患。5、懶漢式的面試題;