前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >23种设计模式之单例模式

23种设计模式之单例模式

作者头像
用户2146693
发布2019-08-08 11:44:35
2650
发布2019-08-08 11:44:35
举报
文章被收录于专栏:架构师进阶架构师进阶

概念

单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

在Java语言中,这样的行为能带来两大好处。 1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于一些重量级的对象而言,是非常可观的一笔系统开销。 2. 由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

角色

单例模式的参与者非常简单,只有单例类和使用者两个。 1. 单例类,提供单例的工程,返回单例类。 2. 使用者,获取并使用单例类。

基本结构

单例模式的核心在于通过一个接口返回唯一的对象实例。

这里写图片描述
这里写图片描述

饿汉模式

饿汉模式的单例,在JVM加载单例类时,单例对象就会被建立。如果此时,这个单例类在系统中还扮演者其他角色,那么在任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会被用到。

代码语言:javascript
复制
//饿汉模式
public class HungrySingleton {
    //利用静态变量来记录singleton的唯一实例
    private final static HungrySingleton uniqueInstance=new HungrySingleton();

    /** * 构造器私有化,只有singleton内部才可以调用 * 确保不会被其他代码实例化 */
    private HungrySingleton(){
        System.out.println("HungrySingleton is create");
    }

    public static HungrySingleton getInstance(){
        return uniqueInstance;
    }
    //其他角色
    public static void createString(){
        System.out.println("createString in HungrySingleton");
    }

    public static void main(String[] args) {
        HungrySingleton.createString();
    }
}

运行结果: HungrySingleton is create createString in HungrySingleton

懒汉模式

懒汉模式,实现延迟加载,确保系统启动时没有额外的负载,提高系统在相关函数调用时的反应速度。

线程不安全的懒汉

代码语言:javascript
复制
//线程不安全的懒汉模式
public class NoSafeSingleton {
    //利用静态变量来记录singleton的唯一实例
    private static NoSafeSingleton uniqueInstance;

    /** * 构造器私有化,只有singleton内部才可以调用 * 确保不会被其他代码实例化 */
    private NoSafeSingleton(){
    }

    //线程不安全
    //第一个线程进来判断 uniqueInstance == null,还没有new 出实例的时候 。
    // 这个时候第二个线程也进来了,判断的uniqueInstance 也是 null,然后也会 new 出实例的
    public static NoSafeSingleton getInstance(){
        if (null==uniqueInstance){
            uniqueInstance=new NoSafeSingleton();
        }
        return uniqueInstance;
    }
}

线程安全的懒汉

为了使用延迟加载引入的同步关键字反而降低了系统性能。

代码语言:javascript
复制
//线程安全的懒汉模式-实现延迟加载
public class SyncLazySingleton {
    private SyncLazySingleton() {
        System.out.println("SyncLazySingleton is create");
    }

    //instance初始值赋予null,确保系统启动时没有额外的负载
    private static SyncLazySingleton instance = null;

    //使用同步关键字,防止多个实例被创建(多线程环境),synchronized保证线程安全
    public static synchronized SyncLazySingleton getInstance() {
        if (instance == null) {
            instance = new SyncLazySingleton();
        }
        return instance;
    }

    //synchronized保证线程安全,降低了系统性能
    public static void main(String[] args) {
        new Thread(){
            public void run(){
                long bg = System.currentTimeMillis();
                for (int i = 0; i < 1000000; i++) {
// HungrySingleton.getInstance();
                     SyncLazySingleton.getInstance();
                }
                System.out.println("spend:" + (System.currentTimeMillis() - bg)+"ms");
            }
        }.start();
    }
}

HungrySingleton is create spend:5ms

SyncLazySingleton is create spend:22ms

内部类实现单例

使用内部类的方式实现单例,既可以做到延迟加载,也不必使用同步关键字,是一种比较完善的实现。

代码语言:javascript
复制
//安全的懒汉模式-使用内部类实现单例 ,实现延迟加载
public class StaticSingleton {
    private StaticSingleton(){
        System.out.println("StaticSingleton is create");
    }

    //JVM加载 StaticSingleton时不会初始化内部类SingletonHolder
    //当方法getInstance()被调用时,才会加载getInstance()
    private static class SingletonHolder{
        private static StaticSingleton instance=new StaticSingleton();
    }

    public static StaticSingleton getInstance(){
        return SingletonHolder.instance;
    }

    public static void main(String[] args) {
        StaticSingleton instance=StaticSingleton.getInstance();
        System.out.println(instance);
    }
}

单例序列化

代码语言:javascript
复制
//序列化和反序列化可能会破坏单例
public class SerSingleton implements Serializable {

    //私有构造器阻止被实例化
    private SerSingleton() {
    }

    private static class SingletonHolder {
        private static final SerSingleton instance = new SerSingleton();
    }

    public static SerSingleton getInstance() {
        return SingletonHolder.instance;
    }

    //序列化和反序列化可能会破坏单例
    //readResolve method to preserve singleton property
    //阻止生成新的实例,总是返回当前对象
    private Object readResolve(){
        //Return the true one SerSingleton and let garbage collector
        // take care of the SerSingleton impersonator.
        return SingletonHolder.instance;
    }

}

最简洁的单例

代码语言:javascript
复制
//最简洁的单例模式
//无偿地提供了序列化机制,绝对防止多次实例化
public enum SingletonEnum {
    INSTANCE;

    public static void main(String[] args) {
        SingletonEnum singletonEnum = SingletonEnum.INSTANCE;
        SingletonEnum singletonEnum1 = SingletonEnum.INSTANCE;

        System.out.println(singletonEnum == singletonEnum1);
        System.out.println(singletonEnum.getClass());
    }
}

true class org.wuxinshui.boosters.designPatterns.singleton.SingletonEnu

破坏单例

通过反射机制,强行调用单例类的构造函数,生成多个单例,破坏单例模式。

StaticSingleton中添加计数器。

代码语言:javascript
复制
    public static final AtomicInteger counter=new AtomicInteger();
    private StaticSingleton(){
        counter.incrementAndGet();
        System.out.println("The "+(counter.get())+" StaticSingleton instance is created");
    }
代码语言:javascript
复制
//利用反射破坏单例模式
public class ReflectSingleton {
    public static void main(String[] args) throws Exception {
        StaticSingleton singleton = StaticSingleton.getInstance();

        Constructor constructor=singleton.getClass().getDeclaredConstructor();

        //值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
        // 值为 false 则指示反射的对象应该实施 Java 语言访问检查。
        constructor.setAccessible(true);

        StaticSingleton singleton2= (StaticSingleton) constructor.newInstance();
        StaticSingleton singleton3= (StaticSingleton) constructor.newInstance();

        System.out.println("singleton2==singleton3 :"+(singleton2==singleton3));
    }
}

运行结果:

代码语言:javascript
复制
The 1 StaticSingleton instance is created
The 2 StaticSingleton instance is created
The 3 StaticSingleton instance is created
singleton2==singleton3 :false
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • 角色
  • 基本结构
  • 饿汉模式
  • 懒汉模式
    • 线程不安全的懒汉
      • 线程安全的懒汉
        • 内部类实现单例
        • 单例序列化
        • 最简洁的单例
        • 破坏单例
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档