2016-12-14 67 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的内容,我认为它不会完成这项工作,也许我错了它的内容,并会再次阅读它。我可以同步整个方法,但它会减慢一切,但我认为我可以使线程安全。 –