【问题标题】:Singleton's other members辛格尔顿的其他成员
【发布时间】:2013-08-08 19:42:48
【问题描述】:

我的问题很笼统,所以我分成了两部分,并尝试用我目前所知道的尽可能具体。

第一部分

单例拥有自己的私有静态实例。关于单例的一些问题:
1。它的成员也应该是静态的,还是取决于要求?
2。如果 1. 的答案是肯定的,那么如果所有成员都属于该类,那么以私有实例变量开头的意义何在?
3。是否需要私有实例,因为 JVM 需要一个可引用对象(单例)来保持其(JVM)生命周期的长度?

第二部分

需要在 tomcat 托管的 Web 应用程序中进行多个并发远程调用(该应用程序将 GWT 用于某些组件,因此如果一个好的解决方案需要,我可以使用 servlet 来满足上述要求)。目前,我创建了一个带有cached thread pool 的执行程序服务,我将callables(每个可调用包含一个端点配置)传递到其中,用于需要此类调用的每个单独的流程流。对我来说,如果线程池由多个流共享,而不是生成它们自己的池,那将是有意义的。持有静态线程池的单例会是一个很好的解决方案吗?

【问题讨论】:

标签: java tomcat web-applications executorservice threadpoolexecutor


【解决方案1】:

需要注意的是,区分单例(只有一个实例的类/对象)的概念和通过持有一个自身的单个静态实例的类来实现这一点的设计模式很重要,该类在全局静态名称空间。单例的概念在设计中经常被使用,但是通过单例设计模式来实现它却经常被反对。

在下文中,单例用于指代具体的设计模式。

第 1 部分

  1. Singleton 的成员不必是静态的,通常也不是。
  2. 见 1。
  3. 单例(设计模式)需要一个自身的实例,以便将该实例返回给单例的用户,并保持对自身的引用处于活动状态以避免垃圾收集(如您所建议的那样)。如果没有这个单一实例,对象本质上就不是单例设计模式的实现。您可以创建一个只为其创建单个实例的类,并将该类传递到需要它的位置(避免使用全局静态命名空间),这基本上是避免使用单例模式的推荐方法。

第 2 部分:

共享您的线程池可能是明智的(但取决于您的要求),这可以通过多种方式完成。一种方法是创建一个池并将该池传递(注入)到需要它的类中。通常的建议是使用 Spring 之类的东西来为你处理这个问题。

使用单例也是一种选择,但是即使您的线程池在这里被封装在单例中,通常仍然最好将这个单例(最好通过接口引用)注入到依赖对象中(通过 setter 或 in他们的构造函数)而不是让你的对象静态地引用单例。造成这种情况的原因有很多,测试、灵活性和对实例化顺序的控制就是一些例子。

【讨论】:

    【解决方案2】:
    1. Singleton 的成员不必是静态的。
    2. 对第 1 点的回答无效。
    3. 单例自身的实例也不必是私有的。如果单例中有任何其他非静态成员,则需要将实例存储到静态成员(公共或私有)。如果有任何非静态成员(这取决于您的要求),那么您需要一个实例来访问该成员(是的,如果该成员是非静态的,JVM 需要一个可引用对象)

    【讨论】:

      【解决方案3】:
      1. 单例成员不需要是静态的
      2. 看第1点
      3. 单例实例必须是静态的(当然)并且必须通过静态方法访问;成瘾必须有一个私有构造函数来防止创建新实例

      public class SingletonNumber10 {  
        public static SingletonNumber10 getInstance() {
          if(null == instance) {
            instance = new SingletonNumber10(10);
          }
          return instance;
        }
        private int number;
        private static SingletonNumber10 instance;
        private SingletonNumber10(int number) {
          this.number = number;
        }
        public int getNumber() {
          return this.number;
        }
        public static void main(String[] args) {
          System.out.println(SingletonNumber10.getInstance());
          System.out.println(SingletonNumber10.getInstance());
        }
      }
      

      【讨论】:

        【解决方案4】:
        A singleton holds a private static instance of itself. 
        

        并非总是如此,事实上,这甚至不是 Java 中最好的方法。

        public enum Director {
        
           INSTANCE;
        
           public int getFive() {
             return 5;
           }
        
        }
        

        是一个完全有效的单例,与拥有其自身私有静态实例的类相比,它更有可能保持唯一存在的副本。

        1. Should it's members also be static
        

        不,成员不应该是静态的,因为这样就不需要类,因此不需要该类是单例。所有静态例程都存在代码维护问题,类似于 C/C++ 函数。即使使用单例您不会有多个实例要处理,但将方法从一个实例中分离出来可以为您在未来改变代码提供某些能力。

        2. If the answer to 1. is unequivocally yes.
        

        不是,所以不需要回答#2。

        3. Is the private instance needed because the JVM needs a 
           referable object (THE singleton) to hold on to for the
           length of its (JVM's) life?
        

        不,私有实例是必需的,因为您必须有能力确定构造函数是否在访问之前被调用。这通常通过检查实例变量是否为空来完成。考虑到竞争条件和类加载器的考虑,要使这样的代码正确是非常困难的。使用枚举技术,您可以确保只有一个实例,因为 JVM 内部不会受到相同类型的竞争条件的影响,即使它们是,也只能保证一个实例呈现给程序环境。

        There is a requirement to make multiple concurrent remote calls within
        a tomcat hosted web application (the app utilizes GWT for some components,
        so I can utilize a servlet for this aforementioned requirement if a good 
        solution requires this). Currently, I create an executor service with a cached 
        thread pool into which I pass my callables (each callable containing an endpoint
        configuration), for each individual process flow that requires such calls. To 
        me it would make sense if the thread pool was shared by multiple flows, instead
        of spawning pools of their own. Would a singleton holding a static thread pool be
        a good solution for this?
        

        这取决于。池中的线程将做什么?如果它是一个线程来处理任务,最终它们都会被长时间运行的任务所束缚,可能会饿死其他关键处理。如果您有大量任务要执行,也许重组类似于 NIO 中使用的回调模式的处理实际上可能会给您更好的性能(其中一个线程处理许多任务的回调调度,没有池) .

        在您提出解决问题的第二种方法或提供有关操作环境的更多详细信息之前,所提出的唯一解决方案通常是一个好的解决方案。

        PS。请不要扩展环境的细节。问题提交过程很简单,因此如果您想扩展第二部分,请将其作为独立问题重新提交。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-29
          • 1970-01-01
          相关资源
          最近更新 更多