完美的单例

2018-01-10  本文已影响24人  0x5947

一、常见的单例实现方式

方式一(静态常量)

public final class Singleton implements Serializable {
  private static final Singleton INSTANCE = new Singleton();
  private Singleton(){
  }
  public static Singleton getInstance(){
    return INSTANCE;
  }
}

方式二(内部类)

public final class Singleton implements Serializable {
  public static class Inner{
    private static final Singleton INSTANCE = new Singleton();
  }
  private Singleton(){
  }
  public static Singleton getInstance(){
    return Inner.INSTANCE;
  }
}

方式三(懒加载)

public final class Singleton implements Serializable {
  private static final Singleton INSTANCE;
  private Singleton(){
  }
  public static Singleton getInstance(){
    if(INSTANCE == null){
      synchronized(Singleton.class){
        if(INSTANCE == null){
          INSTANCE = new Singleton();
        }
      }
    }
    return INSTANCE;
  }
}

二、常见单例实现方式的问题

  1. 方式一的问题在于类加载时候即加载实例。
  2. 方式二看起来好像没什么问题,在使用的时候才会加载内部类。
  3. 方式三需要线程同步开销,效率不高。

除了以上提到的问题,他们在序列化的情况下会存在一个通用的问题;如果你使用RMI发送这个单例对象,你会得到一个新的实例。

如果要解决这个问题,你需要在类中添加一个readResolve()方法,这样在反序列化的时候可以直接返回已有的实例用以替换序列化的数据,代码就像下面这样:

 public final class Singleton implements Serializable {
    //省略其它代码......
    ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
 }

三、完美的单例实现

  1. 方式一

     public final class PerfectSingleton implements Serializable {
       public static class Inner{
         private static final PerfectSingleton INSTANCE = new PerfectSingleton();
       }
       private PerfectSingleton(){
         if(Inner.INSTANCE != null){
           throw new Error("denied access.");
         }
       }
       public static PerfectSingleton getInstance(){
         return Inner.INSTANCE;
       }
       private Object readResolve() throws ObjectStreamException{
         return Inner.INSTANCE;
       }
     }
    
  2. 方式二

     public enum Singleton{
         INSTANCE;
     }
    

总结:方式一可以很好的实现懒加载问题,线程安全问题,反序列化问题,防反射攻击,但是比较繁琐;如果图省事建议直接使用枚举实现,安全又便捷

上一篇 下一篇

猜你喜欢

热点阅读