2016-12-14 38 views
4

這不是討論Singleton是好還是壞。這是關於創建單身人士。我理解辛格爾頓的方式是,它是一個在任何時候都應該存在多於一個對象的類。這就是說,如果幾個類同時實例化一個單例,那麼它們將共享該單例的單個實例。
單身人員的問題在於,一旦創建它,​​它將在應用程序的持續時間內存在。使用我的方法,您可以創建並隨時收集單身垃圾,如果它不再被使用。那麼我需要一個枚舉(Singleton!)來創建所有其他的Singleton。我認爲我的方法是反射和序列化安全,但我不確定線程​​是否有問題。
我的方法來創建單情況如下:這是創建Singleton線程安全的方法嗎?

首先任何類,它想成爲單身必須擴展以下類

public abstract class Singleton { 
    public Singleton(SingletonFactory.SingletonParam singletonParam) { 
     if (singletonParam == null) { 
      throw new NullPointerException("singletonParam cannot be null)"); 
     } 
    } 

    // For singleton to release resources.  
    public abstract void destroy(SingletonFactory.SingletonParam singletonParam); 
} 

SingletonParam將是不能有一個抽象類,內部類對象,它是一個多態意義上的SingletonParam,在其容器類的外部實例化。
這不是要讓子類在運行時擴展Singleton類。它是由具有靜態實例的單例類組成的。我的方法不需要單例類的任何靜態實例。
容器是下面的類

注:讀斯蒂芬C中的答案後,我作出改變,以初始化從構造函數中的HashMap和我不明白爲什麼它不是線程安全的。

public enum SingletonFactory { 
    INSTANCE; 

    enum SingletonList { 
     A, 
     B, 
     ...... 
    } 

    private final HashMap<String, SingletonInfo> mfSingletonInfoHashMap = new HashMap<>(); 

    // Added after @Stephen C answer 
    SingletonFactory() { 
     mfSingletonInfoHasmap.put(A, final new SingletonInfo()); 
    // put all the members of the SingletonList here. 
     At this time the Singleton member of the SingletonInfo is null. 
     It will be instantiated when a class call getSingleton 
    } 

    private class SingletonInfo { 
     final Set callingObjects = new HashSet(); 
     Singleton singleton; 
    } 

    public Object getSingleton(SingletonList inList, Object object) { 
     final SingletonInfo singletonInfo = mfSingletonInfoHashMap.get(inList); 
     synchronized (singletonInfo) { 
       if (singletonInfo.callingObjects.add(object)) { 
        if (singletonInfo.singleton == null) { 
         singletonInfo.singleton = createSingleton(singletonClassName); 
        } 
       } else { 
        throw new RuntimeException("getSingleton(" + singletonClassName + ") has already been called and not released");     
       } 
     return singletonInfo.singleton; 
    } 

    public void releaseSingleton(SingletonList inList, Object object) { 
      SingletonInfo singletonInfo = mfSingletonInfoHashMap.get(inList); 

      synchronized (singletonInfo) { 
      singletonInfo.callingObjects.remove(object); 
      if (singletonInfo.callingObjects.isEmpty()) {    
       singletonInfo.singleton.destroy(new SingletonParam() { 
      }); 
      singletonInfo.singleton = null; 
      } 
     } 
    } 

    private Singleton createSingleton(SingletonList inList) { 
     switch(inList) { 
      case SingletonA: 
       return new SingletonA(new SingletonParam() {}); 
      ...... 
     } 
    } 

    public abstract class SingletonParam { 
     private SingletonParam() { 

     } 
    } 
} 

遠高於並不完全正確,因爲你必須擴展包含在SingletonInfo的CallingObjects落實參考平等和默認實現不等於HashSet的。

由於​​一個子類的實例無法通過調用SingletonFactory.INSTANCE.getSingleton(you_singleton_class_name, this)

+1

你爲什麼不使用'WeakReference'? – shmosel

+0

WeakReference是什麼? –

+0

給你想要成爲垃圾收集者的單身人士。 – shmosel

回答

5

原始版本不是線程安全的實例的SingletonFactory外,你可以創建一個單獨的對象的唯一方法是。 getSingleton方法正在讀取並更新HashMap而沒有同步任何內容。


我看到有可能出現的問題時,沒有SingletonInfo聯營公司與一個單獨的類的名字呢。

正確。


這是一個關於代碼的更新版本:

在這種情況下,我可以填充我的HashMap的所有空CallingObjecs和空辛格爾頓單身類名,然後在SingletonInfo同步。這聽起來是對的嗎?

是的,但前提是:

  1. 初始化發生在SingletonFactory構造,
  2. HashMap中安全地公佈,
  3. 沒有什麼變化HashMap中後,它一直是工廠一直建。

但是,這看起來會打敗您最初實施的優點之一;也就是說,單件工廠是先驗的知識的單身人士。

更好的方法(即保留原始嘗試解決方案的優點的方法)將是同步對HashMap的訪問,或使用ConcurrentHashMap ...及其特殊的原子操作。


由於我學編程只是編碼和不正規的培訓......

至少需要閱讀Java併發一個很好的教科書,如果你要學會正確使用Java併發。嘗試戈茨等人。

(你必須要明白Java併發的原則。你不可能通過反覆試驗來學習他們。)

它(IMO)關於你們這麼專注於讓Singleton設計模式的工作原理,當「收到的智慧」是單身人士是一個壞主意。你有沒有考慮過依賴注入和它的優點?

另一件事是,這些不是真正的單身人士。

  • 您的Singleton類的隱含語義與其名稱相矛盾。可以有多個實例Singleton ...

  • 有沒有什麼可以阻止某人創建給定Singleton子類的多個實例。鑑於您的實施方法,爲了讓工廠能夠正常工作,需要爲每個suclass建立非私有構造函數。

  • 除非你聲明你的Singleton的子類爲final,這將提供另一條路線來打破單一性。

總之,我不相信你正在構建的這個基礎設施將會實現你更好地實現(真正)單例的目標。

+0

它讀取HashMap,但CallingObjectst已同步,因此它不在if(singletonInfo.callingObjects.add(object))線程必須等待,如果另一個線程也想獲得相同的單例對象並鎖定? –

+0

我看到那裏可能有一個問題,當沒有SingletonInfo與單身人士類名稱關聯。在這種情況下,我可以使用空的CallingObjecs和null Singleton將所有單例類名填充到散列表中,然後在SingletonInfo上同步。這聽起來是對的嗎? –

+0

我知道我必須在構造函數中初始化hashmap,但我不明白爲什麼如果我更改了值,初始化之後沒有hashmap的鍵會導致問題。爲什麼它不保存在SingletonInfo中a = get(singletonclassname)然後同步(a)。我可以看到死鎖但沒有不一致的問題。我很久以前讀過關於ConcurrentHashmap的內容,我認爲它不會完成這項工作,也許我錯了它的內容,並會再次閱讀它。我可以同步整個方法,但它會減慢一切,但我認爲我可以使線程安全。 –

相關問題