单例模式
在当前进程中,通过单例模式创建的类有且只有一个实例。
特点:
1. 保证在一个JVM中,该对象只有一个实例存在
2. 构造器必须是私有的,外部类无法通过调用构造器方法创建该实例
3. 没有公开的set方法,外部类无法调用set方法创建该实例
4. 提供一个公开的get方法获取唯一的这个实例
优点:
1. 减少系统开销,减低内存使用频率
2. 避免对资源的重复占用
饿汉模式
把对象提前实例化,外部第一次获取这个类的对象时就直接存在这个类,省去创建的开销
//饿汉模式
class HungrySingleton{
//1.私有构造函数,保证不能实例化本类
private HungrySingleton(){}
//2. 创建一个类的实例化对象
private static HungrySingleton hungrySingleton = new HungrySingleton();
//3. 创建一个get方法,返回一个实例
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
懒汉模式
对象没有被提前实例化,外部第一次获取这个类的对象时是空的,需要初始化,赋值
线程不安全的模式
多个线程调用getInstance方法来获取Singleton的实例是,可能会导致实例化了两个对象
// 懒汉模式
class LazySingleton{
//1.私有构造函数,保证不能实例化本类
private LazySingleton(){}
//2. 自己创建一个类的实例化
private static LazySingleton singleton;
//3. 创建一个get方法,返回实例
public static LazySingleton getInstance(){
//判断singleton是否为null,如果为null,即判定需要实例化
if (singleton == null) {
singleton= new LazySingleton();
}
return singleton;
}
}
线程安全模式
// 懒汉模式
class LazySingleton{
//1.私有构造函数,保证不能实例化本类
private LazySingleton(){}
//2. 自己创建一个类的实例化 (volatile保证不会发生重排序)
private volatile static LazySingleton singleton;
//3. 创建一个get方法,返回实例
public static LazySingleton getInstance(){
//判断singleton是否为null,如果为null,即判定需要实例化
if (singleton == null) {
//同步块,线程安全的创建实例
synchronized (LazySingleton.class){
// 再次检测实例是否存在
if (singleton == null){
singleton= new LazySingleton();
// 字节码层
//JIT 即时编译 CPU
//1. 分配空间
//2. 初始化
//3. 引用赋值
}
}
}
return singleton;
}
volatile的作用:
1. 防止指令重排序,对象的实例化包含创建和赋值
2. 保证内存可见,volatile修饰的变量,不会被本地缓存,所有线程对该对象的读写都会第一时间同步到主内存。
懒汉模式和饿汉模式的区别
两者的根本区别在于对象是否别提前实例化,以及线程的安全问题