单例模式的定义:保证一个类只有一个实例,并且提供一个全局访问点
使用场景:重量级对象,不需要多个实例,如线程池,数据库连接池
类图:一个私有的变量singleton,一个私有的构造方法,一个公共的全局访问点
一、懒汉模式:延迟加载,只在真正实用的时候才开始实例化
public class LazySingleton {
private static volatile LazySingleton sInstance; //定义一个私有的静态变量,volatile是为了线程安全,防止字节码级别的指令重排
//一定要有的私有的构造函数,防止在外部进行实例化
private LazySingleton() {
}
//公有的全局访问点
public static LazySingleton getInstance() {
//实例不为空时才进行创建,避免创建多个实例
if (null == sInstance) {
//为了线程安全,如果两个线程同时进入里面则会创建两个不同的实例,故要加锁
synchronized (LazySingleton.class) {
//里面要再此进行判断,因为有可能两个线程同时进入这里
if (null == sInstance) {
sInstance = new LazySingleton();
}
}
}
return sInstance;
}
}
二、饿汉模式:类初始化时就进行加载
注:由于sInstance是静态的,因此在类加载时就会进行初始化,因此这里只有有一个实例。所以饿汉模式实际上是由jvm类加载机制来保证实例的唯一性
类加载过程:
- 加载二进制数据到内存中,生成对应的class数据结构
- 连接:a.验证 b.准备(给类的静态成员变量赋默认值) c.解析
- 初始化:给类的静态变量赋初值
public class HungrySingleton {
private static HungrySingleton sInstance = new HungrySingleton();//static类型,基于jvm的类加载机制来实现单例
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return sInstance;
}
}
三、 静态内部类方式:其实也是个懒加载模式,只有在调用getInstance的时候才会进行类初始化。也是利用jvm的类加载机制来保证实例唯一性的
public class InnerClassSingleton {
private static class InnerClassHolder {
private static InnerClassSingleton sInstance = new InnerClassSingleton();
}
private InnerClassSingleton() {
}
public static InnerClassSingleton getInstance() {
return InnerClassHolder.sInstance;
}
}