3

我的问题很笼统,所以我分成两部分,并尽量用我目前所知道的来具体说明。

第一部分

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

第二部分

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

4

4 回答 4

1
  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());
  }
}
于 2013-08-08T20:01:21.740 回答
1

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

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

第1部分

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

第2部分:

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

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

于 2013-08-08T19:58:09.697 回答
1
  1. Singleton 的成员不必是静态的。
  2. 对第 1 点的回答无效。
  3. 单例自身的实例也不必是私有的。如果单例中有任何其他非静态成员,则需要将实例存储到静态成员(公共或私有)。如果有任何非静态成员(这取决于您的要求),那么您需要一个实例来访问该成员(是的,如果成员是非静态的,JVM 需要一个可引用对象)
于 2013-08-08T19:47:25.823 回答
1
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。请不要扩展环境的细节。问题提交过程很简单,因此如果您想扩展第二部分,请将其作为独立问题重新提交。

于 2013-08-08T20:31:25.240 回答