面试常问的设计模式——单例模式

本文详细介绍了单例模式的八种常见实现方法,包括饿汉式、懒汉式、双重检查、静态内部类和枚举,强调了单例模式的使用场景、优点以及注意事项,特别是重点讲解了双重检查模式以确保线程安全和高效性。
摘要由CSDN通过智能技术生成

大家好,我是程序员阿药。今天和大家分享的是面试中设计模式部分常问的一种:单例模式。

我了解到的单例模式一共八种,两种饿汉式、三种懒汉式、双重检查、静态内部类、枚举。双重检查方式一般问到的比较多,相对也比较复杂,下面也会详细介绍。

介绍之前先说点别的。

一、为什么要使用单例模式,好处?

单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

二、怎么使用单例模式,方法,注意事项?

当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new。单例类的构造方法一定要私有化

三、单例模式使用的场景?

需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。

下面开始详细介绍各种单例模式。

1. 饿汉式(静态变量实现)


class Singleton {

    /**
     * 1.构造器私有化,外部不能new
     */
    private Singleton() {

    }

    /**
     * 2.本类内部创建对象实例
     */
    private final static Singleton INSTANCE = new Singleton();

    /**
     * 3.提供一个共有的静态方法,返回实例对象
     */
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

2. 饿汉式(静态代码块实现)


class Singleton {

    /**
     * 1.构造器私有化,外部不能new
     */
    private Singleton() {

    }

    /**
     * 2.本类内部创建对象实例
     */
    private static final Singleton INSTANCE;

    static {
        INSTANCE = new Singleton();
    }

    /**
     * 3.提供一个共有的静态方法,返回实例对象
     */
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

饿汉式是立即加载的方式,无论是否会用到这个对象,都会加载。如果在构造方法里写了性能消耗较大,占时较久的代码,比如建立与数据库的连接,那么就会在启动的时候感觉稍微有些卡顿。

3. 懒汉式(静态方法实现)


class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

    /**
     * 提供一个静态共有方法,当使用到的时候,采取创建instance
     * 实际开发不推荐,线程不安全
     */
    public static Singleton getInstance() {
        // (此处线程不安全,多个线程有可能创建多个对象)
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

4. 懒汉式(同步方法实现)


class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

    /**
     * 提供一个静态共有方法,当使用到的时候,采取创建instance
     * 添加同步方法,解决线程安全问题
     * 实际开发不推荐,效率低
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

5. 懒汉式(同步代码块实现)

class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

    /**
     * 提供一个静态共有方法,当使用到的时候,采取创建instance
     * 添加同步代码块,解决线程安全问题
     * 实际开发不推荐,效率低
     */
    public static Singleton getInstance() {
        synchronized (Singleton.class) {        
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

懒汉式是延迟加载的方式,只有使用的时候才会加载。并且有线程安全的考量。使用懒汉式,在启动的时候,会感觉到比饿汉式略快,因为并没有做对象的实例化。但是在第一次调用的时候,会进行实例化操作,感觉上就略慢。

6. 双重检查(重点)

class Singleton {

    private static volatile Singleton instance;

    private Singleton() {

    }

    /**
     * 提供一个静态共有方法,当使用到的时候,采取创建instance
     * 添加双重检查代码,解决线程安全问题,同时解决懒加载问题,同时保证了效率
     * 实际开发推荐
     */
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查模式中当有一个线程创建对象成功后,由于instance对象使用volatile修饰保证了对象的可见性,其它线程会立即知道对象成功创建成功,待竞争锁成功的线程再进入同步代码块后将不会二次创建对象;同时,以后到来的线程也不再需要进入同步代码块判断对象创建成功,通过同步代码块外部的条件判断即可立即返回。

注意:

volatile可以保证变量的可见性和有序性,不可以保证原子性。instance对象使用volatile修饰除了通过可见性保证其它线程立即可见外,在创建单例对象时也通过其有序性保证了对象的成功创建。

对象创建分为1.申请空间、2.初始化对象、3.指向申请的空间三步。如果在创建过程中不保证其有序性,创建顺序变成1、3、2的话,那么如果有新的线程到来,在执行同步代码块外的条件判断时发现对象不为null立即返回;但此时对象并未完成初始化,最终将导致对象无法使用。

7. 静态内部类


class Singleton {

    /**
     * 构造器私有化
     */
    private Singleton() {

    }

    /**
     * 写一个静态内部类,该类中有一个静态属性Singleton
     */
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    /**
     * 提供一个静态共有方法,直接返回SingletonInstance.INSTANCE
     */
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

8. 枚举


enum Singleton {

    INSTANCE;
}

以上内容如果有写的不好的地方欢迎大家批评指正。

今天想分享的就是这些,我是程序员阿药,喜欢的小伙伴可以点赞、收藏支持一下哦。

更多文章可以关注我的微信公众号:“程序员阿药”。

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值