什麼是單例設計模式?
單例設計模式就是一種控制執行個體化對象個數的設計模式。
為什麼要使用單例設計模式?
使用單例設計模式可以節省記憶體空間,提高性能。因為很多情況下,有些類是不需要重複産生對象的。
如果重複産生對象的話,會導緻大量的記憶體空間被占用,性能降低。
例如:在程式啟動中,加載已儲存的資料資訊。這些資料資訊是由一個單例對象統一讀取,其他程式隻需要通過這個單例對象擷取加載的資料資訊即可。
單例設計模式分為餓漢式和懶漢式。餓漢式是在系統加載類的時候就會自動提供類的執行個體化對象如Computer computer。
懶漢式是在第一次使用的時候進行執行個體化對象處理。
餓漢式單例設計模式實作源碼:
class Computer{
//1、私有化 Computer 構造函數
private Computer(){
System.out.println("私有化 Computer 構造函數");
}
public void printInfo(){
System.out.println("Computer 類使用的就是單例設計模式");
}
// 2、調用私有化 Computer 構造函數并将computer屬性設定為static
private static Computer computer = new Computer();
// 3、提供getCompter()方法,便于調用
public static Computer getCompter(){
return computer;
}
}
public class Demo {
public static void main(String[] args) {
// 産生單例對象
Computer computer = Computer.getCompter();
// 調用printInfo()方法
computer.printInfo();
}
}
運作結果:
私有化 Computer 構造函數
Computer 類使用的就是單例設計模式
餓漢式單例設計模式的實作過程分析:
1、所有新的執行個體化對象的産生都會調用構造方法,如果無法正常調用構造方法的話,也就不能産生新的執行個體化對象。
如果想控制執行個體化對象個數的話,那麼就應該控制構造函數。是以首先将該類的構造方法定義為私有方法。
private Computer(){
System.out.println("私有化Computer 構造函數");
}
2、類的構造方法私有化後,在類的外部就不能産生執行個體化對象。但是Private 修飾的構造方法可以在類的内部通路。
如果要通路Private 修飾的構造方法,可以在類的内部調用構造函數。
private Computer computer = new Computer();
3、computer 作為普通屬性,隻有在執行個體化對象産生之後才能被調用。由于類的外部無法産生執行個體化對象,如果想擷取
computer 屬性,可以将computer 屬性設定為static。
private static Computer computer = new Computer();
4、對于private 屬性 computer來說,如果想在類的外部擷取該屬性,則需要通過getComputer()方法擷取。
public static Computer getCompter(){
return computer;
}
由于餓漢式在類加載的時候就完成了對象執行個體化,如果程式始終沒有用到這個執行個體化對象,那麼就會造成記憶體空間的浪費。
為了不浪費記憶體空間,懶漢式是在第一次使用的時候進行執行個體化對象處理。
懶漢式單例設計模式實作源碼:
class Computer{
//1、私有化 Computer 構造函數
private Computer(){
System.out.println("私有化 Computer 構造函數");
}
public void printInfo(){
System.out.println("Computer 類使用的就是單例設計模式");
}
// 2、調用私有化 Computer 構造函數并将computer屬性設定為static
private static Computer computer;
// 3、提供getCompter()方法,便于調用
public static Computer getCompter(){
// 懶漢式,按需建立 即在第一次使用的時候進行執行個體化對象
if(computer == null){
computer = new Computer();
}
return computer;
}
}
public class Demo {
public static void main(String[] args) {
// 産生單例對象
Computer computer = Computer.getCompter();
// 調用printInfo()方法
computer.printInfo();
}
}
私有化 Computer 構造函數
Computer 類使用的就是單例設計模式
懶漢式單例設計模式的實作源碼分析:
為了避免執行個體化的對象始終沒有被使用,造成記憶體空間的浪費,是以增加了對執行個體化對象的判斷,
即如果執行個體化對象為null 則建立執行個體化對象。
// 懶漢式,按需建立 即隻有在第一次使用的時候才進行執行個體化對象
if(computer == null){
computer = new Computer();
}
但是如果在多線程下,會出現這樣的情況即一個線程進入了if 語句, 另一個線程也通過了if語句。
這樣就産生了多個執行個體化對象。 為了避免這樣的問題,可以采用雙重加鎖機制。
雙重加鎖機制優化懶漢式源碼:
class Computer{
//1、私有化 Computer 構造函數
private Computer(){
System.out.println("私有化 Computer 構造函數");
}
public void printInfo(){
System.out.println("Computer 類使用的就是單例設計模式");
}
// 2、調用私有化 Computer 構造函數并将computer屬性設定為static
private volatile static Computer computer;
// 3、提供getCompter()方法,便于調用
public static Computer getCompter(){
// 第一次檢查
if(computer == null){
// 加鎖
synchronized (Computer.class){
// 第二次檢查
if (computer == null){
computer = new Computer();
}
}
}
return computer;
}
}
public class Demo {
public static void main(String[] args) {
// 産生單例對象
Computer computer = Computer.getCompter();
// 調用printInfo()方法
computer.printInfo();
}
}
私有化 Computer 構造函數
Computer 類使用的就是單例設計模式
雙重加鎖機制優化懶漢式源碼分析:
// 2、調用私有化 Computer 構造函數并将computer屬性設定為static
private volatile static Computer computer;
// 3、提供getCompter()方法,便于調用
public static Computer getCompter(){
// 第一次檢查
if(computer == null){
// 加鎖
synchronized (Computer.class){
// 第二次檢查
if (computer == null){
computer = new Computer();
}
}
}
return computer;
}
1、volatile可以保證多線程下的可見性即保證了子線程的會跟主線程的一緻。
2、當thread2,進入第一個if(computer == null) 語句,子線程的computer為空的,thread2釋放資源給thread3。
3、當thread3,進入第一個if(computer == null) 語句,子線程的computer為空的,thread3釋放資源給thread2。
4、當thread2,進入第二個if(computer == null) 語句,執行computer = new Computer(),執行個體化對象computer,volatile修飾的變量computer,會馬上同步到主線程的變量computer,執行完成後thread2釋放資源給thread3。
5、當thread3,進入第二個if (computer == null) 語句,此時子線程的computer不為空,是以thread3不再會重複執行個體化computer。