什么是单例模式
- 该类只有一个实例
- 构造方法是私有的
- 有一个获取该类对象的静态方法getInstance()
应用场景
- 一个国家只有一个主席
- 如果此时的限定必须是抽象出来的类只能是一个对象,这个时候就需要使用单例模式
懒汉式
什么是懒汉式
- 懒汉式是当用到这个对象的时候才会创建,即是在getInstance()方法创建这个单例对象
优缺点
- 只有用到的时候才会创建这个对象,因此节省资源
- 线程不安全
- 我们知道一旦我们使用了懒汉式就是在getInstance()方法中创建这个单例对象,那么不可避免的就是线程安全问题
实现
1 | /** |
从上面的代码中我们可以知道一旦使用多线程创建对象,那么就会出现线程不安全,最后创建出来的就不是单例了
测试代码如下
1 | public class MainTest { |
解决线程不安全
- 线程同步锁(synchronized)
- 我们知道每一个类都有一个把锁,我们可以使用线程同步锁来实现线程同步方法
- 但是使用线程同步锁浪费资源,因为每次创建实例都需要请求同步锁,浪费资源
1 | public synchronized static SignalLazy getInstance() { |
- 双重校验
- 双重校验: 两次判断单例对象是否为 null,这样的话,当当线程经过这个判断的时候就会先判断,而不是等待,一旦判断不成立,那么就会继续执行,不需要等待
- 相对于前面的同步方法更加节省资源
1 | public class SignalTonDoubleCheck { |
- 匿名内部类 (推荐使用)
- 我们知道静态变量、静态代码块、静态方法都是在类加载的时候只加载一次
1 | public class SignalTonInnerHolder { |
- 一旦加载SignalTonInnerHolder类的时候就会加载其中的静态类,随之加载的就是其中的创建对象语句,因此在类加载的时候就完成了创建,这个和我们后面说的饿汉式有点相同
饿汉式
什么是饿汉式
- 在类加载的时候就创建单例对象,而不是在getInstance()方法创建
- 所谓的饿汉式就是利用静态成员变量或者静态语句块在类加载的时候初始化,并且只初始化一次,因此这个是线程安全的,但是在没有用到的时候就初始化,那么是浪费资源
优缺点
- 还没用到就创建,浪费资源
- 类加载的时候就创建,线程安全
实现
1 | /* |
测试
1 | public class MainTest { |
总结
- 饿汉式在类加载的时候就会创建单例对象,因此浪费资源
- 懒汉式在用到的时候才创建,节省资源,但是线程不安全,但是我们可以使用匿名内部类的方式使其线程安全
- 一般在使用的时候会使用懒汉式的匿名内部类的实现和饿汉式的创建方式
笔者有话说
- 最近建了一个微信交流群,提供给大家一个交流的平台,扫描下方笔者的微信二维码,备注【交流】,我会把大家拉进群