这种创建Singleton线程的方法是否安全?

时间:2016-12-14 04:38:47

标签: java singleton

这不是关于Singleton是好还是坏的讨论。它是关于创建单身人士。我理解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类。它是通过拥有静态实例的单例类。我的方法不需要单例类的任何静态实例 容器是以下类

注意:在阅读了Stephen 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,以通过引用实现相等性,并且在默认实现中不相等。

由于SingletonParam的子类的实例无法在SingletonFactory之外实例化,因此创建单例对象的唯一方法是调用SingletonFactory.INSTANCE.getSingleton(you_singleton_class_name, this)

1 个答案:

答案 0 :(得分:5)

原始版本不是线程安全的。 getSingleton方法正在读取和更新HashMap,而不会同步任何内容。

  

当没有SingletonInfo与单例类名相关联时,我发现可能存在问题。

正确。

这是关于代码的更新版本:

  

在这种情况下,我可以使用空的CallingObjecs和null Singleton填充我的hashmap以及所有单例类名,然后在SingletonInfo上进行同步。听起来不错吗?

是的,前提是:

  1. 初始化发生在SingletonFactory构造函数
  2. 安全发布了hashmap,
  3. 在构建工厂之后,没有任何更改hashmap。
  4. 但是,这似乎会破坏您最初实施的优势之一;即单身人士工厂不是先验单身人士的知识。

    更好的方法(即保留原始尝试解决方案优势的方法)是同步访问HashMap,或使用ConcurrentHashMap ...及其特殊的原子操作

      

    因为我只是通过编码学习编程而没有正式的培训......

    如果您要学习正确使用Java并发,至少需要阅读有关Java Concurrency的优秀教科书。试试Goetz等人

    (您需要了解Java并发的原理。您不太可能通过反复试验来学习它们。)

    (IMO)关于你如此专注于使单身人士设计模式发挥作用,当“接受的智慧”是单身人士是一个坏主意。您是否考虑过依赖注入及其优势?

    另一件事是这些不是真正的单身人士。

    • Singleton类的隐含语义与其名称相矛盾。 Singleton ...

    • 可能有多个实例
    • 没有什么可以阻止某人创建给定Singleton子类的多个实例。鉴于您的实现方法,每个蔗类都需要有一个非私有构造函数,以便工厂工作。

    • 除非您将Singleton子类声明为final,否则这将提供另一条破坏单身人士的途径。

    简而言之,我不相信您正在构建的这种基础设施将实现您更好地实施(真正的)单身人士的目标。