Java單例模式的寫法

第一種寫法: 懶漢式單例


class Singleton{
private static Singleton singleleton=null;

pulic static Singleton getInstance(){
if(singleleton==null){
    singleleton=new Singleton()
    }
return singleleton;
}

private Singleton(){

singleleton=new Singleton();

    }
}

特點:這種寫法是線程不安全的,他無法保證同時不被多個線程訪問,適合在單線程環境下使用。

要想保證線程安全,可以參考下面三種寫法:

1)使用synchronized關鍵字


class Singleton{

private static Singleton singleleton=null;

pulic static synchronized Singleton getInstance(){
if(singleleton==null){
    singleleton=new Singleton()
}
return singleleton;
}

private Singleton(){
singleleton=new Singleton();
}


}

特點:相比上個方法,在靜態方法前多加了個synchronized關鍵字,使同一時間只能有一個線程訪問該代碼塊。

2)雙重檢查鎖定


class Singleton{

private static Singleton singleleton=null;

pulic static Singleton getInstance(){
if(singleleton==null){
    synchronized(Singleton.class){
    if(singleleton==null){
        singleleton=new Singleton();
        }
    }
}
return singleleton;
}

private Singleton(){
singleleton=new Singleton();
}


}

特點:經過兩次判定,第一次檢測到實例爲空時,增加同步,同步後再次檢測到實例爲空時,才創建對象實例。有效防止了在多線程環境下創建多個實例的問題。

3)靜態內部類實現


class Singleton{

private singleton(){}

private static class SingleBuilder{
    private static Singleton singleton=new Singleton();          //就像private int int=1
}

public static Singleton getInstance(){
    return SingleBuilder.singleton;
}

}

特點:Java中靜態內部類可以訪問其外部類的成員屬性和方法,同時java規定靜態內部類只在首次調用時被加載,因此實現了懶漢式,所以他只被加載一次,所以是線程安全的


2.餓漢式:


class Singleton{

private static Singleton singleleton=new Singleton();

pulic static Singleton getInstance(){
return singleleton;
}

private Singleton(){}

}

特點:餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以後不再改變,所以天生是線程安全的。


3.登記式:


public class Singleton {  
private static Map< String,Singleton> map = new HashMap< String,Singleton>();  
static{  
    Singleton single = new Singleton();  
    map.put(single.getClass().getName(), single);  
}  
//保護的默認構造子  
protected Singleton(){}  
//靜態工廠方法,返還此類惟一的實例  
public static Singleton getInstance(String name) {  
    if(name == null) {  
        name = Singleton.class.getName();  
        System.out.println("name == null"+"--->name="+name);  
    }  
    if(map.get(name) == null) {  
        try {  
            map.put(name, (Singleton) Class.forName(name).newInstance());  
        } catch (InstantiationException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        } catch (ClassNotFoundException e) {  
            e.printStackTrace();  
        }  
    }  
    return map.get(name);  
}  

public static void main(String[] args) {  
    Singleton3 single = Singleton.getInstance(null);  
}  
}  

登記式單例實際上維護了一組單例類的實例,將這些實例存放在一個Map(登記薄)中,對於已經登記過的實例,則從Map直接返回,對於沒有登記的,則先登記,然後返回。 內部實現還是用的餓漢式單例。

4.使用volatile 關鍵字


class Singleton{
 private static volatile Singleton Instance=null;
 public Singleton() {
 }

 public static Singleton getInstance(){
   if(Instance==null){
       synchronized (Singleton.class) {
           if (Instance == null) {
               Instance = new Singleton();
           }
       }
   }
    return Instance;
  }
}

volatile 保證在實例對象創建後快速通知其他線程該對象的實例已經存在,不需要重複創建了。

發佈了38 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章