單例模式
推薦 Java 常見面試題
什么是單例模式 ?
確保程式中一個類只能被實體化一次,實作這種功能就叫單例模式
單例模式的好處是什么 ?
- 方便控制物件
- 節省資源減少浪費
怎么實作單例模式 ?
- 構造私有化
- 呼叫靜態方法回傳實體
- 確保物件的實體只有一個
常見的單例模式有哪些 ?
- 餓漢式
把物件創建好,需要使用的時候直接用就行
饑腸轆轆 非常著急
- 懶漢式
- 由于餓漢式容易浪費資源,比如類里 有
public static修飾的一個方法test(),即可不創建實體就可訪問到懶不到萬不得已不創建實體,什么時候用什么時候創建
懶漢式的缺點呢 ?
執行緒不安全 但是可以控制
如何控制,下面會講
代碼實作餓漢式
創建
Singleton.java類
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
//構造方法私有化
private Singleton1(){
}
//get方式獲取物件
public static Singleton1 getInstance(){
return INSTANCE;
}
}
創建
TestSingleton.java類
public class TestSingleton{
public static void main(String[] args) {
Singleton1 st1 = Singleton1.INSTANCE;
Singleton1 st2 = Singleton1.getInstance();
//return true
System.out.println(st1.hashCode() == st2.hashCode());
//return true
System.out.println(st1 == st2);
}
}
代碼實作懶漢式
創建
Singleton2.java類
public class Singleton2 {
private static Singleton2 INSTANCE;
//構造方法私有化
private Singleton2(){
}
//get方式獲取物件
public static Singleton2 getInstance(){
if (INSTANCE == null) {
INSTANCE = new Singleton2();
}
return INSTANCE;
}
}
x修改
TestSingleton.java類
Singleton2 a = Singleton2.getInstance();
Singleton2 b = Singleton2.getInstance();
//ture
System.out.println(a == b);
注意: 再有的情況下懶漢式執行緒不安全比如多執行緒
舉例說明 執行緒不安全
修改
Singleton2.java類
public static Singleton2 getInstance(){
if (INSTANCE == null) {
try {
Thread.sleep((int) Math.random() * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton2();
}
return INSTANCE;
}
修改
TestSingleton.java類
Callable<Singleton2> c = new Callable<Singleton2>() {
@Override
public Singleton2 call() throws Exception {
return Singleton2.getInstance();
}
};
//創建兩個執行緒池
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton2> f1 = es.submit(c);
Future<Singleton2> f2 = es.submit(c);
Singleton2 a = f1.get();
Singleton2 b = f2.get();
/**
* 有可能兩種情況
* 1. 判斷是否一致:false
* 2. 判斷是否一致:true
*/
System.out.println("判斷是否一致:" + (a == b));
為什么會這樣呢 ?
- 因為第一個執行緒 if (INSTANCE == null) 進去之后觸發 sleep() 執行緒休眠
- 第二個執行緒就緊跟著 if (INSTANCE == null) 這時 INSTANCE 還是等于null,隨后進入執行緒休眠
- 這樣他兩個都創建了實體,一共創建兩次所以導致執行緒不安全
怎么解決執行緒不安全 ?
解決
懶漢式執行緒不安全的方法
- 使用
synchronized同步鎖- 使用靜態內部類
使用 synchronized 同步鎖
修改
Singleton2.java類
public static Singleton2 getInstance(){
//提高效率 已經new過后不需要再等著資源
if (INSTANCE == null) {
//可以使用同步鎖 完成執行緒安全
synchronized (Singleton1.class) {
if (INSTANCE == null) {
try {
Thread.sleep((int) Math.random() * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton2();
}
}
}
return INSTANCE;
}
- 再次運行
TestSingleton.java測驗 就會回傳true- 但是還是有一個問題,第一個執行緒已經創建好了,第二個執行緒還需要再次進入
synchronized塊等待資源的控制權.可以在外面加上if判斷INSTANCE == null即可提高效率
使用靜態內部類
因使用
synchronized同步鎖,代碼看起來不雅觀,所以可以使用靜態內部類,達到執行緒安全
修改
Singleton2.java類
public class Singleton2 {
//構造私有化
private Singleton2(){
}
//在內部類被加載時,才創建
//靜態內部類 不會隨著外部類加載,初始化 它是一個獨立的 當用這個類時才會加載初始化
//在內部類加載和初始化,所以執行緒是安全的
private static class Inner{
private static final Singleton2 INSTANCE = new Singleton2();
}
//get 方式獲取靜態內部類的INSTANCE
public static Singleton2 getInstance(){
return Inner.INSTANCE;
}
}
小結
并不能說明 懶漢式 要強于 餓漢式,可以根據專案需求,來使用其中一種模式
再次推薦 保你面試必過的 java面試題
本文就先說到這里,有問題歡迎留言討論
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/122639.html
標籤:Java
上一篇:Es6中的常用新特性
