一篇文章看懂单例模式——饿汉式、懒汉式

何为单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

思路

如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。然后再外部通过类名直接调用getIntance方法获取类的实例。因此需要将getInstance方法设置为static,而get方法里边要调用私有的对象变量,因此对象变量也要设置成static。

因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

饿汉式 vs 懒汉式

饿汉式:
  • 特点:立即加载,即在使用类的时候已经将对象创建完毕。
  • 优点:实现起来简单;没有多线程安全问题。
  • 缺点:当类被加载的时候,会初始化static的实例,静态变量被创建并分配内存空间,从这以后,这个static的实例便一直占着这块内存,直到类被卸载时,静态变量被摧毁,并释放所占有的内存。因此在某些特定条件下会耗费内存
public class Singleton {
    private Singleton(){}
    private static Singleton singleton = new Singleton();
    public static Singleton getInstance(){
        return singleton;
    } 
}

懒汉式(线程不安全):
  • 特点:延迟加载,即在调用静态方法时实例才被创建。
  • 优点:实现起来比较简单;当类被加载的时候,static的实例未被创建并分配内存空间,当静态方法第一次被调用时,初始化实例变量,并分配内存,因此在某些特定条件下会节约内存
  • 缺点:在多线程环境中,这种实现方法是完全错误的,线程不安全,根本不能保证单例的唯一性。
public class Singleton {
    private Singleton(){};
    private static Singleton singleton ;
    public static Singleton getInstance(){
        if(singleton == null){
            singleton =new Singleton();
        }
        return singleton;
    }
}
懒汉式(线程安全版):

对象初始化的创建是由很多步骤完成的,比如分配空间、初始化、调用构造器等,是一个复杂的过程,有可能上一个进程进去,已经调用了new Singleton,但new对象的过程并没有执行完成,就已经return退出,如果下一个进程再进来,此时单例已经不为空,会返回之前一个进程已经return的单例对象,但是有可能此对象并没有完成调用构造器的初始化过程,因此需要加入volatile关键字,避免指令重排。

volatile 是 Java 中的一个关键字,用于修饰变量,主要用于确保变量在多线程环境下的可见性和禁止指令重排。它在多线程编程中用于解决共享变量的一些并发访问问题。

具体来说,volatile 关键字提供了以下两个主要特性:

  1. 可见性(Visibility): 当一个变量被声明为 volatile,任何一个线程对这个变量的修改会立即被刷新到主内存中,同时,其他线程在读取该变量时会直接从主内存中读取,而不是从线程的本地缓存中读取。这确保了对 volatile 变量的修改对其他线程是可见的,避免了线程之间的数据不一致问题。

  2. 禁止指令重排(Prevent Instruction Reordering): volatile 变量的读写操作会禁止指令重排,保证在代码执行时不会发生意外的顺序变化,从而确保线程间操作的正确性。

public class Singleton {
    private Singleton(){};
    private static volatile Singleton singleton ;
    public synchronized static Singleton getInstance(){
        if(singleton == null){
        	if(singleton == null){
            singleton =new Singleton();
        }
        return singleton;
        }
    }
}

错误方式:

不可以通过这种方式写单例模式,因为在构造器中,使用new新建实例,而新建的实例又会自己调用构造器,行程了无限递归循环调用,会导致StackOverflowException错误

public class Singleton {
    private static Singleton singleton ;

    private Singleton(){
        singleton =new Singleton();//这里会循环调用自己,导致栈溢出
    }
    public static Singleton getInstance(){
        if(singleton == null){
            return Singleton();//开始无限调用构造器
        }
        return singleton;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘成长日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值