單例模式在多線程下的多種實現模式

單例模式在多線程下的多種實現模式
單例模式是23種設計模式中比較常見的設計模式,又由於其代碼量精簡,因此常常會被用在在面試中測試面試者的能力。java

初級的單例模式很簡單面試

實現兩個要求設計模式

1構造方法私有化緩存

2對外提供靜態的,公開的獲取對象的方法安全

因此:初級單例模式以下多線程

public class Singelton {
private Singelton(){}
private static Singelton sin=null;
public static Singelton getSingelton(){
if(sin==null){
sin=new Singelton();
}
return sin;
}ide

}學習


可是這樣就夠了嗎?測試

隨着學習的深刻,咱們知道程序大多數在多線程的環境下運行。這就對咱們的代碼提出了更高質量的要求,要求咱們考慮線程安全問題。線程

僅僅是上面的那段代碼沒法保證線程的安全。因而:

public class SingletonThread {
private SingletonThread() {}
private static SingletonThread st=null;
public synchronized static SingletonThread getSingletonThread(){
if(st==null){
st=new SingletonThread();
}
return st;
}

}

這段代碼考慮到了線程安全,可是,在方法上加鎖代價是否太大了?效率與單線程相近,假設這個方法中有上萬行代碼,在方法上加鎖

是很不划算的。

因此,咱們有更好的方法

1

public final class SingletonOne {//餓漢式,不能實現按需分配
private SingletonOne(){};
private static SingletonOne sin=new SingletonOne();
public static SingletonOne getSingleton(){
return sin;
}
}

利用靜態成員僅在類加載階段執行一次的性質,獲得惟一的對象。

此方法不只線程安全,並且方法簡介。

2咱們可否不一開始就建立類的實例呢?作到按需分配

以下:

public final class SingletonTwo {
private SingletonTwo(){};
public static SingletonTwo setsin(){
return singleton.sin;
}
static class singleton{//內部類不會再外部類加載時加載,故此是按需分配。
private singleton() {};
private static final SingletonTwo sin=new SingletonTwo();

}
}

利用內部類不會在外部類加載時被加載的性質,真正實現了按需分配。


以上兩種方法是極好的,可是也須要根據實際狀況使用,由於類中的方法和屬性都是靜態的,即便被繼承以後也會被隱藏,

不能經過重寫來實現多態,已經失去了被繼承的意義,故此還有另外一種推薦方法:

3

public class SingletonV {
private SingletonV(){}
private volatile SingletonV singleton=null;
public SingletonV getSingleton(){
if(singleton==null){
synchronized (SingletonV.class) {
if(singleton==null){
singleton=new SingletonV();
}
}
}
return singleton;
}
}

這樣類還保留了繼承的意義,一樣要加鎖,可是開銷小得多。利用了關鍵字volatile。

具體用法以下

//java內存模型規定全部的變量都是存在主存當中(相似於前面說的物理內存),//每一個線程都有本身的工做內存(相似於前面的高速緩存)。//線程對變量的全部操做都必須在工做內存中進行,//而不能直接對主存進行操做。而且每一個線程不能訪問其餘線程的工做內存。//這就可能形成一個線程在主存中修改了一個變量的值,//而另一個線程還繼續使用它在本身工做內存中的變量值的拷貝,形成數據的不一致。 //要解決這個問題,把該變量聲明爲volatile(不穩定的)便可,//這就指示JVM,這個變量是不穩定的, 每次使用它都到 主存中 進行讀取。//通常說來,多任務環境下各任務間共享的標誌都應該加volatile修飾。 //Volatile修飾的成員變量在每次被線程訪問時, 都強迫 從共享內存中 重讀 該成員變量的值。//並且,當成員變量發生變化時,強迫 線程將變化值 回寫到共享內存。這樣在任什麼時候刻,//兩個不一樣的線程老是看到某個成員變量的同一個值。

相關文章
相關標籤/搜索