單態模式可能是23種創建模式種最簡單和容易理解的,創建型模式是主要是爲了解決對象的創建的方式,單態則是爲了保證創建的對象的唯一性。
模式場景與說明
有早期編碼經驗的開發者一般在N層應用開發中的業務邏輯層和持久層之間會有數據庫連接的獲取,不管是從緩衝池中獲取還是直接連接JDBC,爲了避免創建多個示例產生資源的浪費,一般會使用單態模式對創建對象進行控制。實際上除此之外,在類似的池化控制中都可以類似的引入,比如線程池等。此類對象創建一般存在:重(類似數據庫連接的獲取)、頻(使用程度較爲頻繁)的特點。
實現方式1
單態模式實現非常簡單,一般只要把握兩個要點,就能快速創建一個單態模式的類:
- 控制構造函數:私有化構造函數保證無法隨意創建對象
- 統一創建對象:在類中提供對象的構建方法並提供公有方法返回創建的實例(一般爲靜態函數)
實現示例
最簡單的示例代碼如下所示
public class Singleton {
// use private key word to avoid being used directly
private Singleton() {}
private static Singleton instance = new Singleton();
// use public method to get singleton instance
public static Singleton getInstance(){
return instance;
}
}
調用方式:Singleton.getInstance();
這裏稍微修改一下,顯示一下輸出內容,特意在構建函數裏添加sleep,可以在多個終端同時啓動,可以驗證並行時仍然使用同一個實例(hashcode相同)。
package com.liumiao;
import java.time.LocalDateTime;
public class Singleton {
// use private key word to avoid being used directly
private Singleton() {
System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
}
private static Singleton instance = new Singleton();
// use public method to get singleton instance
public static Singleton getInstance(){
System.out.println("get Singleton instance: " + LocalDateTime.now());
System.out.println(instance.hashCode());
return instance;
}
}
測試代碼如下
package com.liumiao;
public class TestSingleton extends Thread {
public void run() {
Singleton.getInstance();
}
public static void main( String[] args )
{
TestSingleton thread1 = new TestSingleton ();
TestSingleton thread2 = new TestSingleton ();
thread1.start();
thread2.start();
}
}
執行結果如下
2020-06-26T05:37:58.555119: Single instance creating begins...
2020-06-26T05:37:59.583467: Single instance creating ends...
get Singleton instance: 2020-06-26T05:37:59.583739
140350290
get Singleton instance: 2020-06-26T05:37:59.583756
140350290
實現方式2
由於實現方式1中對於實例的構建在類裝載的時候就已經完成,雖然解決了線程的同步,但是即使沒有使用到這個實例也會加載,這裏修改一下將new的動作移到getInstance中,通過是否爲空來判斷一下是否需要new進行構建對象,示例代碼如下所示:
package com.liumiao;
import java.time.LocalDateTime;
public class Singleton {
// use private key word to avoid being used directly
private Singleton() {
System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
}
private static Singleton instance = null;
// use public method to get singleton instance
public static Singleton getInstance(){
System.out.println("get Singleton instance: " + LocalDateTime.now());
if (null == instance) {
instance = new Singleton();
}
System.out.println(instance.hashCode());
return instance;
}
}
使用同樣的測試代碼,執行結果如下,所示
get Singleton instance: 2020-06-26T05:39:00.137037
get Singleton instance: 2020-06-26T05:39:00.137051
2020-06-26T05:39:00.137567: Single instance creating begins...
2020-06-26T05:39:00.137614: Single instance creating begins...
2020-06-26T05:39:01.162630: Single instance creating ends...
140350290
2020-06-26T05:39:01.162630: Single instance creating ends...
1253458049
可以看到,單態出現了問題,產生了不同的實例(hashcode不同),因爲沒有考慮到線程安全的問題
實現方式3
這裏簡單地使用synchronized來稍作修改, 代碼如下
package com.liumiao;
import java.time.LocalDateTime;
public class Singleton {
// use private key word to avoid being used directly
private Singleton() {
System.out.printf("%s: Single instance creating begins... \n" ,LocalDateTime.now());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: Single instance creating ends... \n" ,LocalDateTime.now());
}
private static Singleton instance = null;
// use public method to get singleton instance
public static synchronized Singleton getInstance(){
System.out.println("get Singleton instance: " + LocalDateTime.now());
if (null == instance) {
instance = new Singleton();
}
System.out.println(instance.hashCode());
return instance;
}
}
使用同樣的測試代碼執行結果如下
get Singleton instance: 2020-06-26T05:42:13.732276
2020-06-26T05:42:13.732766: Single instance creating begins...
2020-06-26T05:42:14.758235: Single instance creating ends...
346203776
get Singleton instance: 2020-06-26T05:42:14.758679
346203776
所以可以看到已經返回了相同的實例了