Java设计模式之单例模式


什么是单例模式

单例模式,是一种经典的设计模式。

设计模式: 在软件开发中会有一些常见的场景,针对这些场景,大佬们总结了一些固定套路,按照套路来实现代码,不容易出错。

单例就是单个实例,单例模式可以保证某一个类在一个程序中只存在一份实例,不会创建多个实例。

实现单例模式

Java 单例模式的实现有很多种写法,本文只介绍两个,饿汉模式懒汉模式
借助 Java 语法来保证某个类,只能有一个实例,不能 new 多个实例。

饿汉模式

类加载的同时,立马创建实例

class Singleton {
    // 类加载的时候就创建实例
    private static  Singleton instance = new Singleton();

    // 设为私有, 使类外不能new
    private Singleton() {}
    
    // 静态方法
    public static Singleton getInstance() {
        return instance;
    }
}

因为没有涉及修改操作,这个已经是线程安全的。

懒汉模式

类加载的时候不创建实例,等到要使用的时候才创建实例

class Singleton {
    // 类加载的时候没有创建实例
    private static Singleton instance = null;
    
    // 禁止外部创建对象
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            // 用到的时候才创建实例
            instance = new Singleton();
        }
        return instance;
    }
}

上面这个懒汉模式的实现是线程不安全的,在首次创建实例时,如果多个线程调用 getInstance 方法,可能会创建出多个实例。

getInstance 方法加上 synchronized 可以解决这个线程安全问题。

class Singleton {
    // 类加载的时候没有创建实例
    private static Singleton instance = null;
    // 禁止外部创建对象
    private Singleton() {}

    synchronized public static Singleton getInstance() {
        if (instance == null) {
            // 用到的时候才创建实例
            instance = new Singleton();
        }
        return instance;
    }
}

但是这样会大大降低效率,因为只有首次创建实例时,才会出现线程安全问题,而在方法上加锁后,任何时候调用 getInstance 都会触发锁竞争,而且加锁 / 解锁的开销也比较高。

解决办法:if 语句判断是否加锁

class Singleton {
	// 类加载的时候没有创建实例
    private static volatile Singleton instance = null;
    // 禁止外部创建对象
    private Singleton() {}
    
    public static Singleton getInstance() {
        // 判断是否加锁
        if (instance == null) {
             synchronized (Singleton.class) { 
             	// 获取到锁后,可能已经隔了一段时间
             	// 需要再判断一下 instance 是否为空
                 if (instance == null) {
                     instance = new Singleton();
                 }
             }
        }
        return instance;
    }
}

上述代码是改进后的线程安全的懒汉模式

1. 使用双重 if 判定
第一重判断是否加锁,第二重是获取到锁后,判断是否要创建实例(多个线程同时通过第一重判定,同时竞争锁,竞争成功的线程创建了实例,后面再拿到锁的线程就被第二重判定挡住了)。
2. 给 instance 加上了 volatile
保证 instance 的内存可见性,避免读取 instance 时出现误差。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值