常用的五种单例模式实现方式

单例模式的关键点

1) 构造方法不对外开放,为private

2) 确保单例类只有一个对象,尤其是多线程模式下

3) 通过静态方法或枚举返回单例对象

4) 确保单例类在反序列化是不会重新创建新的对象

 

单例模式的实现方式

1)  饿汉式

public class Singleton1 {
    /*
    * 饿汉式是在声明的时候就已经初始化Singleton1,确保了对象的唯一性
    *
    * 声明的时候就初始化对象会浪费不必要的资源
    * */
    private static Singleton1 instance = new Singleton1();

    private Singleton1() {
    }

    // 通过静态方法或枚举返回单例对象
    public Singleton1 getInstance() {
        return instance;
    }
}

2)  懒汉式

public class Singleton2 {

    private static Singleton2 instance;

    private Singleton2() {
    }

    /*
    * getInstance 添加了synchronized 关键字,,也就是说 getInstance 是一个同步方法,
    * 这就是懒汉式在多线程中保持唯一性的方式
    *
    * 懒汉式存在的问题是,即是instance已经被创建,每次调用getInstance方法还是会同步,这样就会浪费一些不必要的资源
    * */
    public static synchronized Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }
        return instance;
    }
}

 

3)  Double Check Lock(DCL模式)

    private static Singleton3 instance;

    private Singleton3() {
    }

    /**
     * getInstance 进行了两次判空,第一次判空是为了不必要的同步,第二次判空为了在instance 为 null 的情况下创建实例
     * 既保证了线程安全且单例对象初始化后调用getInstance又不会进行同步锁判断
     * <p>
     * 优点:资源利用率高,效率高
     * 缺点:第一次加载稍慢,由于java处理器允许乱序执行,偶尔会失败
     *
     * @return
     */
    public static Singleton3 getInstance() {
        if (instance == null) {
            synchronized (Singleton3.class) {
                if (instance == null) {
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

 

4)  静态内部类实现单例模式

5)  public class Singleton4 {
    /*
    *当第一次加载Singleton类时并不会初始化SINGLRTON,只有第一次调用getInstance方法的时候才会初始化SINGLETON
    *第一次调用getInstance 方法的时候虚拟机才会加载SingletonHoder类,这种方式不仅能够保证线程安全,也能够保证对象的唯一,
    *还延迟了单例的实例化,所有推荐使用这种方式
    * */
    private Singleton4() {
    }

    public Singleton4 getInstance() {
        return SingletonHolder.SINGLETON;
    }

    private static class SingletonHolder {
        private static final Singleton4 SINGLETON = new Singleton4();
    }
}

 

6)  枚举实现单例模式

public enum SingletonEnum {
    /**
     *枚举是写法最简单的
     * 默认枚举实例的创建时线程安全的,且在任何一种情况下它都是单例,包括反序列化
     * */
    INSTANCE;
}

 

7)  使用容器实现单例

public class Singleton5 {
    /**
     * 将多种类型的单例放到统一的Map将集合中,根据相应的Key获取对应的对象
     *
     * 这种方式是我们可以管理多种类型的单例,可以使用统一接口进行获取操作
     * 降低了使用成本,也隐藏了具体实现,降低了耦合度
     */
    public static Map<String, Object> objMap = new HashMap<String, Object>();

    private Singleton5() {
    }

    public static void registerInstance(String key, Object instance) {
        if (!objMap.containsKey(key)) {
            objMap.put(key, instance);
        }
    }

    public static Object getInstance(String key) {
        return objMap.get(key);
    }
}

 

反序列化时会重新生成对象的问题

    已上几种方法里面 枚举任何一种情况都是单例,不存在这个问题,容器模式只是承载单例的容器所以它本身也不存在这个问题,只有其他三种方式种存在这个反序列话的问题,怎么解决呢?加入如下代码

// 防止反序列化获取多个对象的漏洞
// 实现Serializable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到
//用readResolve()中返回的对象直接替换在反序列化过程中创建的对象
private Singleton4 readResolve() throws ObjectStreamException {
    return SingletonHolder.SINGLETON;
}
  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值