今天看了关于单例模式的视频,在此做个记录。
单例模式
定义:整个程序有且只有一个实例,该类负责创建自己的对象,同时确保只有一个对象被创建。在Java中,一般常用在工作类的实现或创建对象时需要消耗资源
应用场景:当封装的类,加载次数多,每次初始化都会加载很多资源方法等等,为了节约内存,出现了单例模式。
特点:
- 类构造器私有
- 持有自己类型的属性
- 对外提供获取实例的静态方法
饿汉模式
线程安全,比较常用,在访问量比较大或者需要访问的线程较多时使用饿汉模式,可以实现更好的性能。
public class SingletonTestEHan {
private static SingletonTestEHan instance = new SingletonTestEHan();;
private SingletonTestEHan(){}
private SingletonTestEHan getInstance() {
return instance;
}
}
懒汉模式
只有自己调用的时候才会初始化实例(很懒,在第一次使用时才实例化),线程不安全,延迟初始化,不是严格意义上的单例模式。
public class SingletonLanHan {
private static SingletonLanHan instance;
private SingletonLanHan(){}
public static SingletonLanHan getInstance() {
if(instance == null) {
instance = new SingletonLanHan();
}
return instance;
}
双重检查枷锁(Double Check Lock)
线程安全,延迟初始化。这种方式采用双锁机制,安全且在对线程情况下保持多性能。
进行了两场的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于instance = new SingletonTest();对象创建在JVM中可能进行重排序,在多线程访问下存在风险,使用volatile修饰instance 实例变量有些,解决该问题。
public class SingletonTest {
private static SingletonTest instance = null;
private SingletonTest(){}
public volatile static SingletonTest getInstance() {
if(instance == null) {
synchronized (SingletonTest.class) {
if(instance == null) {
instance = new SingletonTest();
}
}
}
return instance;
}
}
静态内部类模式
只有第一次调用getInstance()方法时,虚拟机才加载Inner并初始化instance,只有一个对象可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式,但具体还是根据项目选择
public class SingletonTest001 {
private SingletonTest001(){}
public static SingletonTest001 getInstance() {
return Inner.instance;
}
private static class Inner{
private static final SingletonTest001 instance = new SingletonTest001();
}
}
枚举单例模式
单元素的枚举类型已经成为实现Singleton的最佳方法。
利用枚举的特性,让JVM来帮我们保证线程安全和单一实例的问题。
class Emp{
private Emp(){}
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private Emp emp;
//创建私有化的构造函数
private SingletonEnum(){
emp = new Emp();
}
public Emp getInstance(){
return emp;
}
}
public static Emp getInstance() {
return SingletonEnum.INSTANCE.getInstance();
}
}
public class SingletonEnum {
public static void main(String[] args) {
System.out.println(Emp.getInstance());;
System.out.println(Emp.getInstance());;
System.out.println(Emp.getInstance() == Emp.getInstance());;
}
}