文章目錄
-
-
-
-
- 一、雙重枷鎖的懶漢模式
- 二、餓漢模式
-
-
-
一、雙重枷鎖的懶漢模式
public class Sun {
/**
* 構造私有化
*/
private Sun() {
System.err.println("Sun 對象初始化..........");
}
private static Sun sun;
public static Sun getInSun() {
if (sun == null) {
synchronized(Sun.class){
if (sun==null) {
sun = new Sun();
return sun;
}
}
}
return sun;
}
}
經過雙重驗證+同步代碼塊多線程建立對象測試
for (int i = 0; i <20000; i++) {
new Thread(){
public void run() {
Sun.getInSun();
};
}.start();
}
建立20000個線程同時擷取對象,通過log看,對象确實隻建立了一個
Sun 對象初始化..........
但是這樣就安全了麼?雖然構造方法私有化了,但是我們可以通過反射的方法去建立對象,這種情況下我們的對象還能保證唯一性麼?通過測試看下結果
try {
Class sun = Sun.class;
Constructor constructor = sun.getDeclaredConstructor();
constructor.setAccessible(true);
Sun sun2 = (Sun) constructor.newInstance();
System.out.println(sun2==Sun.getInSun());
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("已經初始化了不能再初始化了");
}
通過反射的方式建立對象,再通過正常擷取對象的方式擷取對象,看兩個對象是一個?通過測試發現,對象被建立了2次,且兩個對象不是同一個對象。那麼這中情況怎麼處理呢?暫時沒有好的方法去處理,因為對象是每次調用的時候才建立,是以看看其他方式是否能解決
Sun 對象初始化..........
Sun 對象初始化..........
false
二、餓漢模式
public class Moon {
private Moon(){
System.err.println("對象被建立了。。。。。。。。。。");
}
private static Moon moon=new Moon();
public static Moon getMoon(){
return moon;
}
}
和之前一樣先測試下,多線程下對象是不是唯一
for (int i = 0; i <20000; i++) {
new Thread(){
public void run() {
Moon.getMoon();
};
}.start();
}
很顯然多線程下,對象唯一性沒毛病
對象被建立了。。。。。。。。。。
接下來我們依舊使用反射的方法去擷取對象和正常情況下擷取對象看是否是同一個對象
try {
Class sun = Moon.class;
Constructor constructor = sun.getDeclaredConstructor();
constructor.setAccessible(true);
Moon sun2 = (Moon) constructor.newInstance();
System.out.println(sun2==Moon.getMoon());
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("已經初始化了不能再初始化了");
}
對象被建立了。。。。。。。。。。
對象被建立了。。。。。。。。。。
false
很顯然依然是建立了多個對象,兩個對象也不相同,也不能保證對象的唯一性,那麼有什麼方法能夠避免這種情況的發生麼?餓漢模式下的單例模式,對象是再類加載的時候去建立的對象,當再去反射擷取對象的時候,這個對象作為類的靜态資源已經存在,可能再構造方法中做處理,判斷對象!=null的時候直接抛出異常,進而阻止反射建立對象。測試一把
public class Moon {
private Moon(){
if (moon!=null) {
throw new NullPointerException();
}
System.err.println("對象被建立了。。。。。。。。。。");
}
private static Moon moon=new Moon();
public static Moon getMoon(){
return moon;
}
}
====================================================================================
通過log可以看出來确實建立一個對象,當通過反射去建立對象直接抛出異常,這個異常可以自己定義,我這為了友善就先傳回一個空指針異常。
對象被建立了。。。。。。。。。。
已經初始化了不能再初始化了