寫一個單例的類
阿新 • • 發佈:2019-02-18
就是寫一個例項化一次的類
即把構造私有化,外部無法例項化他。通過呼叫他的靜態方法,判斷是否例項化了,未例項化則例項化並返回,已例項化則返回已例項化的。
一:
/** * 基於雙重檢查鎖定的單例模式 * @author zongzhimin * */ public class SingleDog4{ /** * 在錯誤示範2的基礎上給instance加 volatile進行修飾 * volatile可以保證instance的可見性禁止上個錯誤示例的那種重排序 */ private static volatile SingleDog4 instance = null; private SingleDog4(){ } public static SingleDog4 getInstance(){//雙重檢查防止多執行緒下出問題 if (null == instance){// 1 synchronized (SingleDog4.class){ if(null == instance) { instance = new SingleDog4();//2 } } } return instance; } public void say(){ System.out.println("Single all the way"); } }
二:
/** * 基於靜態內部類的單列模式 * @author zongzhimin * */ public class SingleDog6{ private SingleDog6(){ } private static class InstanceHolder{ final static SingleDog6 instance = new SingleDog6(); } public static SingleDog6 getInstance(){ return InstanceHolder.instance; } public void say(){ System.out.println("Single all the way"); } }
效能不好:
/** * 這個效能不好 * @author zongzhimin * */ public class SingleDog{ private static SingleDog instance = null; private SingleDog(){ } public static SingleDog getInstance(){//這裡每次獲取例項都要先獲取鎖,效能不好 synchronized (SingleDog.class){ if (null == instance){ instance = new SingleDog(); } return instance; } } public void say(){ System.out.println("Single all the way"); } }
錯誤示範1:
/**
* 錯誤示範1
* @author zongzhimin
*
*/
public class SingleDog2{
private static SingleDog2 instance = null;
private SingleDog2(){
}
/**
* 這裡做了改進將靜態快放在裡面但是這是錯誤的!!!
* 多執行緒下A執行緒到1, B執行緒到2 -->(A判斷instance==null、正好B執行緒執行完2例項化一次)-->(這時A執行緒會進入靜態快再例項化一次。單例失敗)
*
* @return
*/
public static SingleDog2 getInstance(){
if (null == instance){// 1
synchronized (SingleDog2.class){
instance = new SingleDog2();//2
}
}
return instance;
}
public void say(){
System.out.println("Single all the way");
}
}
錯誤示範2:
/**
* 錯誤示範2
* @author zongzhimin
*
*/
public class SingleDog3{
private static SingleDog3 instance = null;
private SingleDog3(){
}
/**
* 這裡在錯誤示範的基礎上做了改進增加一次進入靜態快的判斷!!!在塊裡再判斷一次,避免錯誤示範2裡面的再次例項化
* 但這依然是不正確的:
* 對於2操作: 可以分為 一:分配SingleDog3物件所需空間 二:初始化SingleDog3物件 三:將物件引用寫入instance物件
* 由於重排序在臨界區(靜態快內的操作可以重排序)所以2操作可能是:一、三、二。
* 因此:
* 執行緒A進入靜態快且進行一、三、二的 三這一步(還未走二例項化SingleDog3但是已先給instance變數賦地址)
* 而另一執行緒B進入1,發現instance不為null,然後return instance,此時執行緒A還未走完er,即SingleDog3還未例項化,程式出錯
*
* @return
*/
public static SingleDog3 getInstance(){
if (null == instance){// 1
synchronized (SingleDog3.class){
if(null == instance) {
instance = new SingleDog3();//2
}
}
}
return instance;
}
public void say(){
System.out.println("Single all the way");
}
}