0%

设计模式之单例模式(三)

前言

懒汉模式虽然起到了延迟加载的,但是总的来说这个东西还不是很靠谱,我们只能继续探寻下去。今天我们来看看剩下的三种:双重检查、静态内部类、枚举方式。

单例模式(双重检查)

双重检查,主要是使用 volatile 关键字,声明我们的类中的静态属性

1
package com.yubulang.type06;
2
3
public class Singleton {
4
    private Singleton() {
5
    }
6
7
    private static volatile Singleton instance;
8
9
    // 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
10
    // 同时保证了效率,推荐使用
11
    public static Singleton getInstance() {
12
        if (instance == null) {
13
            synchronized (Singleton.class) {
14
                if (instance == null) {
15
                    instance = new Singleton();
16
                }
17
            }
18
        }
19
20
        return instance;
21
    }
22
}

优缺点分析:

  • 双重检查概念是多线程开发中常使用的,如上面代码所示,我们进行了两次 if (instance == null)检查,这样就可以保证线程安全了。
  • 这样实例化代码只用执行一次,后面再次访问时,判断 if (instance == null),直接 return 实例化对象,也避免的反复进行方法同步。
  • 线程安全;延迟加载;效率较高
  • 结论:在实际开发中,推荐使用这种单例设计模式。

单例模式(静态内部类)

这个方式主要利用了静态内部类的特点,我们会在结论告诉大家为啥。

1
package com.yubulang.type07;
2
3
// 静态内部类, 推荐使用
4
public class Singleton {
5
    private Singleton() {
6
    }
7
8
    // 写一个静态内部类,该类中有一个静态的属性 Singleton
9
    private static class SingletonInstance {
10
        private static final Singleton INSTANCE = new Singleton();
11
    }
12
13
    // 提供一个静态的共有方法,直接返回
14
    public static Singleton getInstance() {
15
        return SingletonInstance.INSTANCE;
16
    }
17
}

优缺点分析:

  • 这种方式采用了类装载的机制来保证初始化实例时只有一个线程
  • 静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才会装载 SingletonInstance 类,从而完成 Singleton 的实例化。
  • 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
  • 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
  • 结论:推荐使用

单例模式(枚举方式)

枚举是 jdk 1.5 提供的,我们可以利用它的特点来进行单例的声明

1
package com.yubulang.type08;
2
3
// 使用枚举方法,可以实现单例,推荐
4
enum Singleton {
5
    INSTANCE;
6
7
    public void method01() {
8
        System.out.println("ok");
9
    }
10
}

优缺点分析:

  • 这借助 JDK 1.5 中添加的枚举来实现单例模式,不仅可以避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
  • Effective Java 作者 Josh Bloch 提倡的方式
  • 结论:推荐使用

总结

我们说了八种单例模式的实现方式,Java 真的吐槽一下方式太多了哈哈哈,那么这么多方式我们只需要记住推荐使用的那几个,我们推荐使用:

  • 饿汉式(静态代码块)——在确定肯定会被使用到时,这样可以避免内存浪费
  • 双重检查
  • 静态内部类
  • 枚举方式

单例模式的注意事项

  • 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
  • 单例模式使用的场景:需要频繁的进行创建和销毁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)