使用单例模式的主要目的是为了确保系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
一.单例模式的特点
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。
二.单例模式通常包含以下几个要素:
-
私有的构造方法:将类的构造方法声明为私有,防止其他代码通过实例化操作创建类的对象。
-
静态成员变量:在类内部定义一个静态的成员变量来持有该类的唯一实例。
-
静态获取方法:提供一个静态的公共方法来获取该类唯一实例的引用。
常用的几种单例模式code:
1.饿汉式
public class CustomManager {
//私有的静态属性,直接创建对象(在类加载的时候就已经创建)
private static CustomManager mInstance = new CustomManager();
// 私有的构造方法,只能在类内部调用,不允许外部创建实例
private CustomManager() {
}
// 公开的获取实例的方法
public static CustomManager getInstance() {
return mInstance;
}
}
2.懒汉式
public class CustomManager {
// 声明一个私有的静态变量instance,用于保存单例对象
private static CustomManager mInstance;
// 私有的构造方法,只能在类内部调用,不允许外部创建实例
private CustomManager() {
}
// 公开的获取实例的方法
public static CustomManager getInstance() {
synchronized (CustomManager.class) {
if (mInstance == null) {
mInstance = new CustomManager();
}
return mInstance;
}
}
}
3.双重检查锁(Double-Checked Locking)
public class CustomManager {
// 声明一个私有的静态变量instance,使用volatile关键字确保可见性和禁止指令重排序
private volatile static CustomManager mInstance;
// 私有的构造方法,只能在类内部调用,不允许外部创建实例
private CustomManager() {
}
// 公开的获取实例的方法
public static CustomManager getInstance() {
//if 避免非必要加锁,提高效率
if (mInstance == null) {
synchronized (CustomManager.class) {
//if 实现单例模式
if (mInstance == null) {
mInstance = new CustomManager();
}
}
}
return mInstance;
}
}
4.静态内部类
public class CustomManager {
// 私有的构造方法,只能在类内部调用,不允许外部创建实例
private CustomManager() {
}
// 公开的获取实例的方法
public static CustomManager getInstance() {
return CustomManagerHolder.INSTANCE;
}
//静态内部类
private static class CustomManagerHolder {
//jvm来执行类加载,一定是单例的,不存在线程安全问题
private static final CustomManager INSTANCE = new CustomManager();
}
}
静态内部类的原理是:当 SingleTon 第一次被加载时,并不需要去加载 SingleTonHoler,只有当 getInstance() 方法第一次被调用时,才会去初始化 INSTANCE,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。getInstance 方法并没有多次去 new 对象,取的都是同一个 INSTANCE 对象。
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕
5.枚举
public enum CustomManager {
/**
* 不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
*/
INSTANCE;
// 可以添加其他方法和成员变量
public void whateverMethod() {
}
}