定义
单例设计模式(Singleton),就是采取一定的方法保证在整个的软件系统中,为了节约硬件资源或保证数据一致性,某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
单例模式属于创建型模式。
要点
- 该类只能有一个实例
- 单例类自行创建实例
构造器私有化 - 向整个系统提供获取这个实例的统一访问方式
对外提供获取该实例对象的方式 (1)直接暴露;(2)公有静态方法
场景
某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
例如:代表 JVM 运行环境的 Runtime 类( 饿汉式 )。
实现
- 饿汉式 - 直接初始化
/**
* 第一种形式:饿汉式 - 直接初始化
*
* 在类装载时完成实例化。利用 classloader 机制避免了线程同步问题。
* 没有达到 Lazy Loading 的效果,如果从始至终从未使用过这个实例,则会造成内存的浪费。
*/
public class Singleton01 {
public static final Singleton01 INSTANCE = new Singleton01();
private Singleton01() {}
}
2.饿汉式 - 枚举
/**
* 第二种形式:饿汉式 - 枚举
*
* JDK 1.5+
* 避免多线程问题,还能防止反序列化重新创建新的对象,Effective Java 作者 Josh Bloch 提倡的方式
*/
public enum Singleton02 {
/**
* 枚举单例
*/
INSTANCE
}
- 饿汉式 - 静态代码块
/**
* 第三种形式:饿汉式 - 静态代码块
*
* 适合复杂实例化
* 线程安全
*/
public class Singleton03 {
public static final Singleton03 INSTANCE;
private String initialInfo;
static {
try {
Properties properties = new Properties();
properties.load(Singleton03.class.getClassLoader().getResourceAsStream("singleton.peroperties"));
INSTANCE = new Singleton03(properties.getProperty("SingletonInfo"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton03(String initialInfo) { this.initialInfo = initialInfo; }
}
- 懒汉式 - 单线程使用
/**
* 第四种形式:懒汉式 - 单线程
*
* 线程不安全
*/
public class Singleton04 {
private static Singleton04 instance;
private Singleton04() {}
public static Singleton04 getInstance() {
if (instance == null) {
instance = new Singleton04();
}
return instance;
}
}
5.== 懒汉式 - 双重判断==
/**
* 第五种形式:懒汉式 - 双重判断
*
* 适用于多线程
* 注意:这里的 instance 类变量需要使用volatile。
*/
public class Singleton05 {
private static volatile Singleton05 instance;
private Singleton05() {}
public static Singleton05 getInstance() {
// 此处判断是为了提高性能
if (instance == null) {
synchronized (Singleton05.class) {
if (instance == null) {
instance = new Singleton05();
}
}
}
return instance;
}
}
- 懒汉式 - 内部类
/**
* 第六种形式:懒汉式 - 内部类
*
* 在内部类初始化时,才创建Singleton实例
* 静态内部类不会随着外部类的加载和初始化而初始化.
* 静态内部类和非静态内部类一样,都是在被调用时才会被加载,它是单独去加载和初始化的,在内部类加载和初始化时创建对象,所以是线程安全的。
*
* 实现懒加载且线程安全,推荐
*/
public class Singleton06 {
private Singleton06() {}
private static class Inner {
private static final Singleton06 INSTANCE = new Singleton06();
}
public static Singleton06 getInstance() {
return Inner.INSTANCE;
}
}
源代码
Click here:Github 地址