一、什么是單例模式
單例模式,指的是一個類中的對象只能有一個,它在內存中只會創建一次對象的設計模式。
二、餓漢式
public class SingleTon {// 私有的構造方法private SingleTon() {};// 1. 餓漢式private static SingleTon instance = new SingleTon(); // 一開始就初始化好// 線程是安全的,// 因為這個實例是一開始就創建好的,無論幾個線程來調,他只是讀這個instance變量,不存在寫public static SingleTon getInstance() { // 對外提供獲取這個實例的方法return instance;}
}
餓漢式的問題是:?一開始就實例化對象,如果實例化過程非常耗時,并且最后這個對象若沒有被使用,白白造成資源浪費?
?
三、懶漢式
public class SingleTonL {private SingleTonL() {};private static SingleTonL instance1 = null;// 2.懶漢式 線程是不安全的public static SingleTonL getInstance() {if (instance1 == null) {instance1 = new SingleTonL(); // 這里面是一個寫入的動作}return instance1;}
}
對于懶漢式這一設計模式,線程是不安全的,針對這個問題,給出了解決方案
方案:使用? synchronized? 關鍵字
??假如有多個線程中都調用了getInstance方法,那么都走到 if (instance== null) 判斷時,可能同時成立,因為instance初始化時默認值是null。這樣會導致多個線程中同時創建instance對象,即instance對象被創建了多次,違背了只創建一個instance對象的初衷。
// 解決上述線程不安全的問題
public class SingleTonL1 {private SingleTonL1() {};private static SingleTonL1 instance1 = null;// 2.懶漢式 線程是不安全的public static SingleTonL1 getInstance() {synchronized (SingleTonL1.class) {if (instance1 == null) {instance1 = new SingleTonL1(); // 這里面是一個寫入的動作}}return instance1;}
}
還有一個問題就是如果instance != null , 按照上述代碼,這個線程也會進入鎖,,,影響執行的效率。需要在前面在進行是否為空判斷
// 解決上述線程不安全的問題
class SingleTonL1 {private SingleTonL1() {};private static SingleTonL1 instance1 = null;// 2.懶漢式 線程是不安全的public static SingleTonL1 getInstance() {if (instance1 == null) { // 先判斷,如果不為null, 則不用加鎖,直接返回synchronized (SingleTonL1.class) {if (instance1 == null) {instance1 = new SingleTonL1(); // 這里面是一個寫入的動作}}}return instance1;}
}
?
多線程下的內存可見性
?當A線程更改了變量instance后,線程B又訪問,此時需要讓線程B訪問到的是變量instance的被更改后的值。(也就是說線程B去取這個變量的時候必須從主存取,不能從緩存取。)
解決方案: volatile
?
?