我最近接受了采访,他向我询问了Singleton Design Patterns有关它们是如何实现的,我告诉他使用静态变量和静态方法我们可以实现Singleton Design Patterns。
他似乎对答案感到满意,但我想知道
任何输入都会对Singleton表示高度赞赏,在处理Singletons时要记住哪些主要内容?
感谢。
答案 0 :(得分:15)
在Java中实现Singleton模式有几种方法:
// private constructor, public static instance
// usage: Blah.INSTANCE.someMethod();
public class Blah {
public static final Blah INSTANCE = new Blah();
private Blah() {
}
// public methods
}
// private constructor, public instance method
// usage: Woo.getInstance().someMethod();
public class Woo {
private static final Woo INSTANCE = new Woo();
private Woo() {
}
public static Woo getInstance() {
return INSTANCE;
}
// public methods
}
// Java5+ single element enumeration (preferred approach)
// usage: Zing.INSTANCE.someMethod();
public enum Zing {
INSTANCE;
// public methods
}
鉴于上面的示例,每个类加载器将有一个实例。
关于在群集中使用单例...我不确定“使用”的定义是什么...是面试者暗示在整个群集中创建单个实例?我不确定这是否有意义......?
最后,在spring中定义一个非单例对象只需通过属性singleton =“false”来完成。
答案 1 :(得分:2)
我不同意@irreputable。
Singleton的范围是Classloader树中的节点。它包含类加载器,任何子类加载器都可以看到Singleton。
了解范围概念非常重要,尤其是在具有复杂类加载器层次结构的应用程序服务器中。
例如,如果您在应用服务器的系统类路径上的jar文件中有一个库,并且该库使用Singleton,则Singleton将(可能)对于部署到的每个“app”都相同应用服务器。这可能是也可能不是一件好事(取决于图书馆)。
类加载器,恕我直言,是Java和JVM中最重要的概念之一,而Singletons正在发挥作用,所以我认为对Java程序员来说“关心”非常重要。
答案 2 :(得分:2)
我发现很难相信这么多答案错过了单身人士的最佳标准练习 - 使用Enums - 这将为你提供一个单例,其范围是类加载器,对于大多数用途来说足够好。
public enum Singleton { ONE_AND_ONLY_ONE ; ... members and other junk ... }
对于更高级别的单身人士 - 也许我很傻 - 但我的倾向是分发JVM本身(并限制类加载器)。然后enum就足够了。
答案 3 :(得分:1)
Singleton通常通过使用静态实例对象(private SingletonType SingletonType.instance
)来实现,该实例对象通过静态SingletonType SingletonType.getInstance()
方法进行了懒惰实例化。使用单身人士存在许多陷阱,事实上,许多人认为单身人士是设计反模式。鉴于有关Spring的问题,面试官可能正在寻找对单身人士的理解,以及他们的陷阱以及这些陷阱的解决方案,称为依赖注入。您可以在Google Guice页面上找到视频,这有助于了解单身人士的陷阱以及DI如何解决此问题。
答案 4 :(得分:1)
3:最后他问是否可以使用带有Clusters的Singleton Object和解释,当我们调用Bean Factory来获取对象时,有没有办法让Spring不实现Singleton Design Pattern?
如果没有技术背景,这个问题的第一部分很难回答。如果集群平台包括对远程对象进行调用的能力,就好像它们是本地对象一样(例如,使用引擎盖下的RMI或IIOP的EJB可能),那么可以这样做。例如,JVM常驻单例对象可以是群集范围的单例对象的代理,最初通过JNDI或其他东西定位/连接。但群集范围内的单例是一个潜在的瓶颈,因为对单个代理之一的每次调用都会导致(昂贵的)RPC到单个远程对象。
问题的第二部分是Spring Bean Factories可以配置不同的范围。默认值是单例(在webapp级别作用域),但它们也可以是会话或请求作用域,或者应用程序可以定义自己的作用域机制。
答案 5 :(得分:0)
静态字段在一个JVM中可以多次出现 - 通过使用差异类加载器,可以多次加载和初始化相同的类,但每个都处于隔离状态,JVM将结果加载的类视为完全不同的类。
我不认为Java程序员应该关心,除非他正在编写一些框架。 “每个虚拟机一个”是一个很好的答案。人们经常这样说,而严格来说他们说的是“每个班级一个人”。
每个群集可以有一个单身人士吗?那是一个概念游戏。我不会欣赏采访者这样说的话。
答案 6 :(得分:0)
您已经涵盖了标准方式。此外,大多数依赖注入方案都有一些方法将类标记为单例;这样,该类看起来就像任何其他类一样,但是框架确保当您注入该类的实例时,它始终是相同的实例。
这就是毛茸茸的地方。例如,如果在Tomcat应用程序上下文中初始化类,则单例实例的生命周期将绑定到该上下文。但是很难预测你的类将被初始化的位置;所以最好不做任何假设。如果你想绝对确保每个上下文只有一个实例,你应该将它绑定为ServletContext的一个属性。 (或者让依赖注入框架来处理它。)
-
我不确定我是否理解这个问题 - 但如果您正在谈论在多个集群节点之间共享一个单例实例,那么我认为EJB使这成为可能(通过远程bean),尽管我已经从未尝试过。不知道Spring是如何做到的。
答案 7 :(得分:0)
Singleton是一种创造模式,因此可以控制对象的实例化。创建单例会强制您自愿或非自愿地放弃对创建对象的控制,而是依靠某种方式来获取对象。
这可以使用静态方法或依赖注入或使用工厂模式来实现。手段无关紧要。在普通受保护构造函数()方法的情况下,使用者perforce需要使用静态方法来访问单例。在DI的情况下,消费者自愿放弃对类的实例化的控制,而是依赖于DI框架将实例注入其自身。
正如其他海报所指出的,java中的类加载器将定义单例的范围。群集中的单身人士通常是“非单一实例”,而是表现出类似行为的实例集合。这些可以是SOA中的组件。
答案 8 :(得分:0)
以下代码来自here
关键点是你应该Override
clone
方法......维基百科example也很有帮助。
public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}
public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}
public Object clone()
throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}
private static SingletonObject ref;
}
答案 9 :(得分:0)
查询1:
创建Singleton的不同方式
Normal Singleton
:静态初始化Lazy Singleton
:双锁单身& :Initialization-on-demand_holder_idiom singleton 看看下面的代码:
public final class Singleton{
private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
public enum EnumSingleton {
INSTANCE;
}
public static void main(String args[]){
System.out.println("Singleton:"+Singleton.getInstance());
System.out.println("Enum.."+EnumSingleton.INSTANCE);
System.out.println("Lazy.."+LazySingleton.getInstance());
}
}
final class LazySingleton {
private LazySingleton() {}
public static LazySingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazySingleton INSTANCE = new LazySingleton();
}
}
相关的SE问题:
What is an efficient way to implement a singleton pattern in Java?
查询2:
每个ClassLoader
创建一个Singleton实例。如果您想避免在Singleton
期间创建Serializaiton
对象,请覆盖以下方法并返回相同的实例。
private Object readResolve() {
return instance;
}
查询3:
要在多个服务器之间实现群集级别Singleton
,请将此Singleton对象存储在Terracotta
,Coherence
等分布式缓存中。
答案 10 :(得分:0)
Singleton是一种创造性的设计模式。
Singleton设计模式的意图:
我在这里展示了三种类型的实现。
及时初始化(在第一次运行期间分配内存,即使您不使用它)
class Foo{
// Initialized in first run
private static Foo INSTANCE = new Foo();
/**
* Private constructor prevents instantiation from outside
*/
private Foo() {}
public static Foo getInstance(){
return INSTANCE;
}
}
首次使用时初始化(或延迟初始化)
class Bar{
private static Bar instance;
/**
* Private constructor prevents instantiation from outside
*/
private Bar() {}
public static Bar getInstance(){
if (instance == null){
// initialized in first call of getInstance()
instance = new Bar();
}
return instance;
}
}
这是另一种Lazy初始化方式,但优点是,此解决方案是线程安全的,无需特殊的语言结构(即volatile或synchronized)。阅读更多SourceMaking.com
class Blaa{
/**
* Private constructor prevents instantiation from outside
*/
private Blaa() {}
/**
* BlaaHolder is loaded on the first execution of Blaa.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class BlaaHolder{
public static Blaa INSTANCE = new Blaa();
}
public static Blaa getInstance(){
return BlaaHolder.INSTANCE;
}
}