黑馬程序員_Singleton模式(單例模式)餓漢式和懶漢式

------- 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、懶漢式的面試題;

發佈了33 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章