单例模式的理解

简介: 谈谈你对单例模式的理解。也算是老生常谈的问题了~~~

一、作用

单个实例

保证我们的实例对象在整个应用程序中只有一个实例

二、创建方式

五种实现方式

2.1 饿汉式

在类加载的时候立即初始化,并且创建单例对象

它绝对线程安全,在线程出现以前就实例化了,不可能存在访问安全问题

优点:不加任何锁,执行效率比较高,用户体验比懒汉单例模式好

缺点:浪费内存,不管用不用都占着内存

publicclassHungrySingleton {
// 直接实例化方式//    private static final HungrySingleton hungrySingleton = new HungrySingleton();privatestaticfinalHungrySingletonhungrySingleton;
// 静态块单例模式static {
hungrySingleton=newHungrySingleton();
    }
privateHungrySingleton(){}
privatestaticHungrySingletongetInstance(){
returnhungrySingleton;
    }
}

2.2 懒汉式

在外部调用的时候才进行实例化,相比较饿汉式避免了资源浪费

在单线程情况下,比较友好。

多线程情况下,会存在线程安全问题

publicclassLazySimpleSingleton {
privateLazySimpleSingleton() {
    }
privatestaticLazySimpleSingletonlazySimpleSingleton=null;
publicstaticLazySimpleSingletongetInstance() {
if (null==lazySimpleSingleton) {
lazySimpleSingleton=newLazySimpleSingleton();
        }
returnlazySimpleSingleton;
    }
}

2.3 双重检测锁(DCL)

基于懒汉式的线程安全问题,有了双重校验锁

publicclassLazyDoubleCheckSingleton {
privatevolatilestaticLazyDoubleCheckSingletonlazyDoubleCheckSingleton=null;
/*** 私有化构造方法,防止直接通过new实例化*/privateLazyDoubleCheckSingleton() {
    }
publicstaticLazyDoubleCheckSingletongetInstance() {
if (lazyDoubleCheckSingleton==null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton==null) {
// 1.分配内存空间 2.执行构造方法,实例化对象 3.把这个对象赋给这个空间// 不加volatile关键字,会造成指令重排,1,3,2lazyDoubleCheckSingleton=newLazyDoubleCheckSingleton();
                }
            }
        }
returnlazyDoubleCheckSingleton;
    }
}

2.4 静态内部类

publicclassStaticSingleton {
publicstaticclassInnerStaticSingleton {
/*** 声明外部类型的静态常量*/publicstaticfinalStaticSingletoninstance=newStaticSingleton();
    }
privateStaticSingleton() {
    }
publicStaticSingletongetInstance() {
returnInnerStaticSingleton.instance;
    }
}

2.5 枚举类型

publicenumEnumSingleton {
INSTANCE;
publicvoidhandleMethod(){
// 业务处理    }
}

综上的五种写法,大多都是在考虑着线程安全问题

2.6 反射爆破问题

私有的构造器,可以通过反射去破坏。

在私有构造器中进行判断,进而抛出异常。

publicstaticvoidmain(String[] args) throwsNoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
LazySimpleSingletoninstance=LazySimpleSingleton.getInstance();
Class<LazySimpleSingleton>clazz=LazySimpleSingleton.class;
Constructor<LazySimpleSingleton>constructor=clazz.getDeclaredConstructor();
constructor.setAccessible(true);
LazySimpleSingletoninstance1=constructor.newInstance();
System.out.println(instance);
System.out.println(instance1);
}
// 结果com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6

2.7 序列化与反序列化破坏单例

LazySimpleSingleton要实现Serializable序列化接口

publicstaticvoidmain(String[] args) throwsNoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException {
LazySimpleSingletoninstance=LazySimpleSingleton.getInstance();
Class<LazySimpleSingleton>clazz=LazySimpleSingleton.class;
Constructor<LazySimpleSingleton>constructor=clazz.getDeclaredConstructor();
constructor.setAccessible(true);
LazySimpleSingletoninstance1=constructor.newInstance();
System.out.println(instance);
System.out.println(instance1);
ObjectOutputStreamoutputStream=newObjectOutputStream(newFileOutputStream("d:/tools/a.txt"));
outputStream.writeObject(instance);
outputStream.flush();
outputStream.close();
ObjectInputStreaminputStream=newObjectInputStream(newFileInputStream("d:/tools/a.txt"));
LazySimpleSingletoninstance2= (LazySimpleSingleton) inputStream.readObject();
inputStream.close();
System.out.println(instance);
System.out.println(instance2);
}
// 结果com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2com.example.validated.design.singleton.LazySimpleSingleton@5e265ba4

我们需要重写readResolve()方法

privateObjectreadResolve() {
returnlazySimpleSingleton;
}

结果:

com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2

说明:readResolve()方法是基于回调的,反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要再创建新的对象。

三、应用

在框架中看到的单例模式

  1. Spring中的Bean对象,默认是单例模式
  2. 相关的工厂对象都是单例,如:Mybatis中的SqlSessionFactory,Spring中BeanFactory
  3. 保存相关配置信息的都是单例,如:Mybatis中的Configuration对象,SpringBoot中的各个xxxAutoConfiguration对象
  4. 应用程序的日志应用,一般都会通过单例来实现
  5. 数据库的连接池的设计也是单例模式
目录
相关文章
|
6月前
|
设计模式 安全
详细讲解什么是单例模式
详细讲解什么是单例模式
|
5月前
|
设计模式 安全 Java
单例模式分享
单例模式分享
23 0
|
6月前
|
设计模式 安全 Java
单例模式
​ 如有错误或有补充,以及任何的改进意见,请在评论区留下您的高见,同时文中给出大部分的示例 如果觉得本文写的不错,不妨点个赞,收藏一下,助力博主产生质量更高的作品 概念 单例模式(Singleton Pattern)是软件设计模式的一种,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于需要频繁创建和销毁同一对象的场景,以减少系统资源的消耗和提高性能。 优缺点 优点: 实例控制:单例模式确保类只有一个实例,可以防止其他对象实例化自己的副本,从而确保所有对象都访问唯一实例。 节约资源:由于系统中只存在一个对象,可以节约系统资源,特别是在需要频繁创建和销毁对象的场景中,可
56 0
|
设计模式 安全 编译器
2023-6-12-第三式单例模式
2023-6-12-第三式单例模式
72 0
|
6月前
|
安全 C++
C++单例模式
C++单例模式
52 1
|
6月前
|
C++
【C++ 单例模式】
【C++ 单例模式】
|
设计模式 安全 Java
单例模式的运用
单例模式的运用
45 0
找对象需要单例模式吗?
单例模式的类只提供私有的构造函数
|
安全 Java
单例模式很简单
《基础系列》
117 0
单例模式很简单
|
存储 安全 调度
单例模式的简单介绍
单例模式的简单介绍