目錄
- Java單例模式的幾種常見實作方式
- 懶漢or餓漢?
- 餓漢:不加鎖,執行緒安全,用起來方便,容易產生垃圾物件
- 單執行緒下的單例模式(懶漢,執行緒不安全)
- 多執行緒下的單例模式(一)(懶漢,執行緒安全)
- 多執行緒下的單例模式(二)(雙重檢測)
Java單例模式的幾種常見實作方式
懶漢or餓漢?
- 懶漢:單例模式延遲加載方式,一開始不給你new物件,你要new再給你new
- 餓漢:上來就給你new好一個物件,你可以直接用(吃),你也沒法new
餓漢:不加鎖,執行緒安全,用起來方便,容易產生垃圾物件
public class SingletonTest1 {
public static void main(String[] args) {
//由于構造方法是私有的,則外界無法實體化該類
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start();
Singleton1 singleton2 = Singleton1.getInstance();
}
}
class Singleton1 {
//類加載時直接通過宣告呼叫構造方法初始化
private static volatile Singleton1 singleton1 = new Singleton1();
//讓建構式為private,這樣該類不會被外部呼叫實體化物件
private Singleton1(){
check();
}
//通過靜態方法提供外界獲取該唯一可用物件的視窗
//直接給你用,你也別想著什么時候創建了
public static Singleton1 getInstance() {
return singleton1;
}
//第一次創建實體就列印
private static void check() {
System.out.println("第一次創建該類的唯一實體才會列印這句話");
}
}
輸出:
第一次創建該類的唯一實體才會列印這句話
單執行緒下的單例模式(懶漢,執行緒不安全)
這種方式只能在單執行緒環境中實作單例模式
public class SingletonTest1 {
public static void main(String[] args) {
//由于構造方法是私有的,則外界無法實體化該類
//Singleton1 singleton1 = new Singleton1();
//只可以通過實體化的方式
Singleton1 singleton1 = Singleton1.getInstance();
Singleton1 singleton2 = Singleton1.getInstance();
singleton1.test();
}
}
class Singleton1 {
//默認初始化為null
private static Singleton1 singleton1;
//讓建構式為private,這樣該類不會被外部呼叫實體化物件
private Singleton1(){}
//通過靜態方法提供外界獲取該唯一可用物件的視窗
//如果唯一的實體沒有創建就負責創建,否則回傳唯一的物件參考
public static Singleton1 getInstance() {
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
//第二次創建就不會新建一個物件,而是傳回之前已經創建的物件實體
return singleton1;
}
//一個實體方法,用于證明實體化成功
public void test() {
System.out.println("測驗方法,證明確實獲得到了唯一實體");
}
//第一次創建實體就列印
private static void check() {
System.out.println("第一次創建該類的唯一實體才會列印這句話");
}
}
輸出:
第一次創建該類的唯一實體才會列印這句話
//顯然第二次獲取實體時只是獲得到了之前創建的實體
測驗方法,證明確實獲得到了唯一實體
多執行緒下的單例模式(一)(懶漢,執行緒安全)
區別在于將方法上鎖(這里也可以采用重入鎖),我們來分析一下具體的作業環境,A執行緒為了檢測是否新建的了實體,對get方法上鎖,開始檢測物件是否為null,并呼叫構造方法,回傳物件...B執行緒試圖中途獲得鎖被阻塞,然后等A執行緒釋放鎖之后,B獲得鎖去檢測是否創建了物件,發現已經創建,就回傳物件釋放鎖...
public class SingletonTest1 {
public static void main(String[] args) {
//由于構造方法是私有的,則外界無法實體化該類
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start();
Singleton1 singleton2 = Singleton1.getInstance();
}
}
class Singleton1 {
//默認初始化為null
private static Singleton1 singleton1;
//讓建構式為private,這樣該類不會被外部呼叫實體化物件
private Singleton1(){}
//通過靜態方法提供外界獲取該唯一可用物件的視窗
//如果唯一的實體沒有創建就負責創建,否則回傳唯一的物件參考
public synchronized static Singleton1 getInstance() {
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
//第二次創建就不會新建一個物件,而是傳回之前已經創建的物件實體
return singleton1;
}
//一個實體方法,用于證明實體化成功
public void test() {
System.out.println("測驗方法,證明確實獲得到了唯一實體");
}
//第一次創建實體就列印
private static void check() {
System.out.println("第一次創建該類的唯一實體才會列印這句話");
}
}
輸出:
第一次創建該類的唯一實體才會列印這句話
多執行緒下的單例模式(二)(雙重檢測)
這里要注意:上鎖解鎖的很消耗時間空間的,而這里無論物件是否存在,都先上鎖,再去檢測,顯然是沒有必要的,當執行緒很多的時候會造成資源大量的浪費~可以先檢測物件是否存在,如果物件不存在再試圖申請鎖去創建資源,則會節約資源并達到執行緒安全的目的——雙重檢測
public class SingletonTest1 {
public static void main(String[] args) {
//由于構造方法是私有的,則外界無法實體化該類
//Singleton1 singleton1 = new Singleton1();
new Thread(() -> {
Singleton1 singleton1 = Singleton1.getInstance();
}).start();
Singleton1 singleton2 = Singleton1.getInstance();
}
}
class Singleton1 {
//默認初始化為null,volatile:主記憶體 作業記憶體
private static volatile Singleton1 singleton1;
//讓建構式為private,這樣該類不會被外部呼叫實體化物件
private Singleton1(){}
//通過靜態方法提供外界獲取該唯一可用物件的視窗
//如果唯一的實體沒有創建就負責創建,否則回傳唯一的物件參考
public static Singleton1 getInstance() {
if (singleton1 == null) {
synchronized (Singleton1.class) {
//兩個賢臣可能都越過了外層的null檢測,所以可能進入后已經不是null了
if (singleton1 == null) {
check();
singleton1 = new Singleton1();
}
}
}
return singleton1;
}
//一個實體方法,用于證明實體化成功
public void test() {
System.out.println("測驗方法,證明確實獲得到了唯一實體");
}
//第一次創建實體就列印
private static void check() {
System.out.println("第一次創建該類的唯一實體才會列印這句話");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/252913.html
標籤:其他
