Java - 单例

Posted

技术标签:

【中文标题】Java - 单例【英文标题】:Java - Singleton [duplicate] 【发布时间】:2015-07-18 01:01:53 【问题描述】:

我有一些关于在 Java 中实现单例模式的问题。

    当我们使用克隆时,可能会有多个单例实例。有什么具体的方法可以预防吗?

    如果我们使用序列化和反序列化创建另一个单例实例会有什么影响?

【问题讨论】:

如果可以创建其他实例,这不是单例。如果您需要克隆或序列化单例的 state,请使用反映其 state 的特殊对象并对其执行克隆/序列化,而不是单例本身。 不,这就是全部的想法。写单例,这样就不会发生。但是想想不要写单例。谷歌禁止他们:code.google.com/p/google-singleton-detector 【参考方案1】:

1) 不要让单例可克隆,没有人会克隆它

2) 如果 Singleton 是 Serializable 并且它不使用 readResolve 来防止重复,那么在反序列化它时会得到重复,并且它不再是 Singleton。影响取决于应用逻辑

【讨论】:

【参考方案2】:

有效的 Java 项目 3: 猫王是你的班级。

public class Elvis 
  private static final Elvis INSTANCE = new Elvis();
  private Elvis()  ... 
  public static Elvis getInstance()  return INSTANCE; 
  public void leaveTheBuilding()  ... 

如果要序列化:

// readResolve method to preserve singleton property
private Object readResolve() 
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
   return INSTANCE;

或者你可以使用枚举:

 // Enum singleton - the preferred approach
 public enum Elvis 
   INSTANCE;
   public void leaveTheBuilding()  ... 

【讨论】:

【参考方案3】:

我不确定你的第二点,但这回答了第一点:

public class SingletonObject 

    /**
     * The one and only instance of this class
     */
    private static SingletonObject ref;

    /**
     * Creates the object. Must not be called more than once.
     */
    private SingletonObject() 
        // no code required
    

    /**
     * Returns a reference to the singleton object
     * @returns The singleton object
     */
    public static synchronized SingletonObject getSingletonObject() 
        if (ref == null) 
            // First call, so create it
            ref = new SingletonObject();
        
        return ref;
    

    /**
     * Prevents cloning of the object.
     * @throws CloneNotSupportedException If method is called
     */
    public Object clone() throws CloneNotSupportedException 
        throw new CloneNotSupportedException(); 
    

您可以简单地覆盖克隆方法。 注意getSingletonObject 是同步的,如果ref 等于null 并且两个线程同时调用该函数,则会阻止创建对象的实例。

【讨论】:

【参考方案4】:

要添加到@Evgeniy Dorofeev 评论,我看不出有任何理由让它可克隆并期望它也是单例。无论出于何种原因,如果它实现了 Cloneable,您始终可以通过覆盖 clone() 方法来引发异常。

【讨论】:

【参考方案5】:
    当我们使用克隆时,可能会有多个 Singleton 实例。有什么具体的方法可以预防吗?

不要实现 Cloneable 接口。当你尝试调用 `clone()~ 时,你会自动得到CloneNotSupportedException

    如果我们使用序列化和反序列化创建另一个单例实例会有什么影响?

是的,您可以使用序列化创建多个版本的单例类。为防止这种情况,请不要实现Serializable 接口,或者如果您想明确 阻止序列化,您可以覆盖writeObject() 以在序列化期间抛出异常。

代码:

   // Double check Singleton   
class Singleton implements Serializable 

    private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException 
        throw new IOException("Serialization is not allowed");
    

    private static final long serialVersionUID = -6022571167467223517L;

    private volatile static Singleton singletonInstance = null;

    private Singleton() 

    

    public static Singleton getInstance() 
        if (singletonInstance == null) 
            synchronized (Singleton.class) 
                if (singletonInstance == null) 
                    singletonInstance = new Singleton();
                

            
        
        return singletonInstance;
    


【讨论】:

以上是关于Java - 单例的主要内容,如果未能解决你的问题,请参考以下文章

Java 设计模式之单例学习与掌握

单例模式

单例工厂适配器装饰器

单例模式(singleton)

单例模式(singleton)

第三梦 单例模式