設計模式-單例模式、多例模式
單例設計模式
正常情況下一個類可以建立多個物件
public static void main(String[] args) {
// 正常情況下一個類可以建立多個物件
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
但是有些時候的某些類, 我們希望只能建立單一的一個物件, 這時候我們需要使用到單例設計模式, 下面我們來介紹一下單例設計模式.
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。
單例設計模式的作用
- 目的: 保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
- 解決的問題: 一個全域性使用的類頻繁地建立與銷燬。
- 什麼時候使用: 當您想控制例項數目,節省系統資源的時候。
單例設計模式的實現步驟
- 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
- 在該類內部產生一個唯一的例項化物件,並且將其封裝為private static型別的成員變數。
- 定義一個靜態方法返回這個唯一物件。
餓漢式
餓漢單例設計模式就是使用類的時候已經將物件建立完畢,不管以後會不會使用到該例項化物件,先建立了再說。很著急的樣子,故被稱為“餓漢模式”。
程式碼如下:
public class Singleton {
// 1.將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
private Singleton() {}
// 2.在該類內部產生一個唯一的例項化物件,並且將其封裝為private static型別的成員變數。
private static final Singleton instance = new Singleton();
// 3.定義一個靜態方法返回這個唯一物件。
public static Singleton getInstance() {
return instance;
}
}
懶漢式
懶漢單例設計模式就是呼叫getInstance()方法時例項才被建立,先不急著例項化出物件,等要用的時候才例化出物件。不著急,故稱為“懶漢模式”。
懶漢式-普通方式【不能用】
(1) 實現步驟
- 私有構造方法
- 建立一個物件的宣告, 但是不例項化.
- 對外暴露一個用於獲取物件的靜態方法
- 判斷物件是否為空
- 如果為空就例項化
- 返回當前物件
(2) 程式碼實現
package com.itheima._01single.demo02;
/**
*
* 懶漢式
* 懶: 上來不著急建立物件, 什麼時候用, 什麼時候建立
*
*/
public class Singleton {
// 1. 私有構造
private Singleton() {}
// 2. 只宣告本類的引用, 後面不建立物件
private static Singleton instance;
// 3. 提供公共的用來獲取本類物件的方法
public static Singleton getInstance() {
// 判斷: 如果instance為null => 建立物件
if (instance == null) {
// 為了看到效果, 所以讓執行緒睡一會
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 什麼時候用, 什麼時候建立
instance = new Singleton();
}
// 如果instance不為null, 直接返回
return instance;
}
}
(3) 優缺點
- 優點: 起到了懶載入的效果
- 缺點: 多執行緒環境下會出現問題, 可能建立出多個例項, 不符合單例的原則.
結論: 在實際開發中不要使用這種方式.
懶漢式 - 同步方法【能用】
(1) 實現步驟
-
私有構造方法
-
類的內部建立物件
-
對外暴露一個用於獲取物件的靜態同步方法
-
判斷物件是否為空
-
如果為空就例項化
-
返回當前物件
-
(2) 程式碼實現
package com.itheima._01single.demo03;
/**
* 懶漢式 - 同步方法
*/
public class Singleton {
// 1. 私有構造
private Singleton() {
}
// 2. 宣告引用
private static Singleton instance; // 例項
// 3. 獲取物件的方法
public static synchronized Singleton getInstance() {
// 判斷, 如果為null, 建立物件
if (instance == null) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton();
}
// 如果不為null, 直接返回
return instance;
}
}
(3) 優缺點
優點: 解決了多執行緒中建立多個物件的問題
缺點: 效率太低, 每次執行都要進入同步方法.
總結: 實際開發中不推薦使用
懶漢式 - 同步程式碼塊【過渡】
(1) 實現步驟
-
私有構造方法
-
類的內部建立物件
-
對外暴露一個用於獲取物件的靜態方法
-
判斷物件是否為空
-
在同步程式碼塊中進行判斷, 如果為空就例項化
-
返回當前物件
-
(2) 程式碼實現
package com.itheima._01single.demo04;
/**
*
* 懶漢式 - 同步程式碼塊
*
* 這種實現方式是有問題的, 我要用這種方式給大家引出最終的BOSS
*
* 剛才使用同步方法的時候, 可以保證只建立一個物件, 但是每一次都要先獲取鎖
*
* 1. 不每一次上來就直接先獲取鎖
* 2. 等判斷完為null, 再獲取鎖, 建立物件
*
*/
public class Singleton {
// 1. 私有構造
private Singleton() {}
// 2. 宣告引用
private static Singleton instance;
// 3. 公共方法
// 把獲取鎖物件的時機延後, 且不滿足條不會獲取鎖(減少了獲取鎖的次數)
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
(3) 優缺點
- 缺點: 想提高同步方法的效率, 但是又出現了多執行緒中建立多個物件的問題
實際開發中不能使用
雙重檢查(Double-Check)【推薦使用】
(1) 實現步驟
- 私有構造方法
- 類的內部建立物件(使用volatile修飾)
- 對外暴露一個用於獲取物件的靜態方法
- 判斷物件是否為空
- 同步程式碼塊
- 在同步程式碼塊中再次判斷物件是否為空
- 如果為空再例項化
- 最後返回當前物件
(2) 程式碼實現
package com.itheima._01single.demo05;
/**
*
* 雙重檢查
*
* 1. 兩個if(instance == null) 的判斷
* 2. 加上volatile關鍵字, 保證共享資料可可見性
*
*/
public class Singleton {
// 1. 私有構造
private Singleton() {}
// 2. 宣告引用
private static volatile Singleton instance;
// 3. 提供獲取物件的方法
public static Singleton getInstance() {
// 如果物件不存在
if (instance == null) {
// 執行緒1, 判斷是null || 執行緒2, 判斷是null
// 同步鎖
// 問題: 多執行緒中有可能建立多個物件
synchronized (Singleton.class) {
if (instance == null) {
// 建立物件
instance = new Singleton();
}
}
}
return instance;
}
}
(3) 優缺點
- 進行兩次null檢查, 可以保證執行緒安全
- 例項化的程式碼只會執行一次, 後面再次訪問的時候直接return例項化的物件, 避免了同步的多次執行.
- 執行緒安全, 懶載入, 效率較高
總結: 實際開發中, 推薦使用這種單例設計模式
雙重檢查單例的圖解
多例設計模式
多例模式,是一種常用的軟體設計模式。通過多例模式可以保證系統中,應用該模式的類有固定數量的例項。多例類要自我建立並管理自己的例項,還要向外界提供獲取本類例項的方法。
實現步驟
1.建立一個類, 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
2.在類中定義該類被建立的總數量
3.在類中定義存放類例項的list集合
4.在類中提供靜態程式碼塊,在靜態程式碼塊中建立類的例項
5.提供獲取類例項的靜態方法
實現程式碼如下
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Multition {
// 定義該類被建立的總數量
private static final int maxCount = 3;
// 定義存放類例項的list集合
private static List instanceList = new ArrayList();
// 構造方法私有化,不允許外界建立本類物件
private Multition() {
}
static {
// 建立本類的多個例項,並存放到list集合中
for (int i = 0; i < maxCount; i++) {
Multition multition = new Multition();
instanceList.add(multition);
}
}
// 給外界提供一個獲取類物件的方法
public static Multition getMultition(){
Random random = new Random();
// 生成一個隨機數
int i = random.nextInt(maxCount);
// 從list集合中隨機取出一個進行使用
return (Multition)instanceList.get(i);
}
}
測試結果
public static void main(String[] args) {
// 編寫一個迴圈從中獲取類物件
for (int i = 0; i < 10; i++) {
Multition multition = Multition.getMultition();
System.out.println(multition);
}
}
多例模式可以保證系統中一個類有固定個數的例項, 在實現需求的基礎上, 能夠提高例項的複用性.
相關文章
- 架構設計:單例模式、多例模式相比較有何不同?架構單例模式
- 設計模式(單例模式)設計模式單例
- [設計模式] 單例模式設計模式單例
- 設計模式-單例模式設計模式單例
- 設計模式 —— 單例模式設計模式單例
- 設計模式 單例模式設計模式單例
- 設計模式——單例模式設計模式單例
- 極簡設計模式-多例模式設計模式
- 多例設計模式設計模式
- 設計模式(一)_單例模式設計模式單例
- 常用設計模式-單例模式設計模式單例
- 設計模式之單例模式設計模式單例
- Java設計模式【單例模式】Java設計模式單例
- Java設計模式 | 單例模式Java設計模式單例
- 001設計模式:單例模式設計模式單例
- # Python設計模式 單例模式Python設計模式單例
- 設計模式一(單例模式)設計模式單例
- 設計模式之☞單例模式設計模式單例
- Java設計模式——單例模式Java設計模式單例
- Java設計模式–單例模式Java設計模式單例
- js設計模式--單例模式JS設計模式單例
- Java設計模式-單例模式Java設計模式單例
- 設計模式(二)——單例模式設計模式單例
- 設計模式之---單例模式設計模式單例
- Java設計模式--單例模式Java設計模式單例
- Python設計模式——單例模式Python設計模式單例
- 設計模式—singleton(單例模式)設計模式單例
- python設計模式-單例模式Python設計模式單例
- 設計模式之單例設計模式設計模式單例
- Java設計模式——單例模式(建立型模式)Java設計模式單例
- 設計模式總結 —— 單例設計模式設計模式單例
- JavaScript設計模式初探--單例設計模式JavaScript設計模式單例
- Javascript設計模式之單例模式JavaScript設計模式單例
- PHP 設計模式之——單例模式PHP設計模式單例
- Javascript設計模式(三)單例模式JavaScript設計模式單例
- golang設計模式之單例模式Golang設計模式單例
- jS設計模式二:單例模式JS設計模式單例
- 前端設計模式(2)--單例模式前端設計模式單例