1. 设计模式说明
单例模式是最常见的设计模式之一。它主要用来保证在应用中只有一个实例,可以对于线程池、数据库连接等重量级应用提高复用率,减少创建以及维持多实例时消耗的大量资源。常见的单例模式的实现方案有懒汉式、饿汉式、枚举、静态内部类四种方案。
2. 单例模式实现方案
2.1 饿汉式单例方案
饿汉式实现比较简单,就是在类加载时直接对创建静态实例并初始化,这样可以避免线程安全问题。也有人认为这是缺点,因为没有延迟加载,所以会在初始化时占用部分资源,导致初始化时间变长。但是如果资源初始化时间比较长的话,还是建议应用启动初始化,这样可以避免第一次访问时响应时间过长的问题。
样例代码如下:
java
public class Singleton1 {
private static Singleton1 instance = new Singleton1();
private Singleton1() {
}
public static Singleton1 getInstance() {
return instance;
}
}
2.2 懒汉式单例方案
针对于饿汉式没有进行延迟初始化的缺点,懒汉式方案也就应运而生。但是对于懒汉式的方案需要注意线程安全问题,问了解决线程安全问题,可以使用双重检查锁的方式。
样例代码如下:
java
public class Singleton {
// 防止指令重排并保证数据可见性
private volatile Singleton instance ;
private Singleton() {
}
public static Singleton getInstance() {
// 只有在实例为空的情况下才会进行实例初始化
if(instance == null){
// 在多线程情况下,可能会存在同时多个实例为空的线程,所以需要使用同步锁
synchronized (Singleton.class){
// 对于进入同步锁的线程,第一个实例化后,后续的线程由于持有的instance依然为空,所以需要再次进行判断
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
懒汉式使用双检锁是为了保证单例多线程读取的安全性,但同时由于代码容易遗漏部分内容,而且对于初学者来说不太容易理解,所以不建议使用。
2.3 静态内部类方案单例方案
静态内部类是一种类似于饿汉式的解决方案。它利用了Java的静态内部类的特点,那就是当Singleton默认不会被实例化,同时,当调用getInstance()方法时,InstanceHolder才会被创建,这样就满足了延迟加载的要求。同时由于是静态类,会由JVM保障实例的唯一性和线程安全性。
样例代码如下:
java
public class Singleton {
private Singleton() {
}
private static final class InstanceHolder {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InstanceHolder.instance;
}
}
2.4 枚举类单例方案
枚举方案也是利用了枚举类型线程安全且只会装载一次的特性。这也是 effective java 作者极力推荐的单例实现模式。
样例代码如下:
java
public enum Singleton {
Instance;
}
3. 推荐方案
- 推荐使用枚举类实现方案。简单、便于理解,还有JVM对单例进行保证。