看!单例模式来咯

92 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:[2021最后一次更文挑战]

写前面

今天主要是设计模式之一的单例设计模式

模式定义

保证一个类只有一个实例,并且提供一个全局访问点

场景:

重量级的对象,不需要多个实例,如线程池,数据库连接池。

1.懒汉模式

1)线程安全问题

2)doublecheck加锁优化

3)编译器(JIT),CPU有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加 volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排。

2.饿汉模式

类加载的初始化阶段就完成了实例的初始化。本质上就是借助于jvm类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安全(JVM以同步的形式来完成类加载的整个过程)。类加载过程:

1)加载二进制数据到内存中,生成对应的Class数据结构

2)连接:a.验证,b.准备(给类的静态成员变量赋默认值),c.解析

3)初始化:给类的静态变量赋初值

只有在真正使用对应的类时,才会触发初始化如(当前类是启动类即main函数所在类,直接进行new操作,访问静态属性、访问静态方法,用反射访问类,初始化一个类的子类等.)

3.静态内部类

1)本质上是利用类的加载机制来保证线程安全

2)只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式。

4.反射攻击实例

Constructor<InnerClassSingleton>declaredConstructor=InnerClassSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
InnerClassSingletoninnerClassSingleton=declaredConstructor.newInstance(); 
InnerClassSingletoninstance=InnerClassSingleton.getInstance();
System.out.println(innerClassSingleton==instance);

5.枚举类型

1)天然不支持反射创建对应的实例,且有自己的反序列化机制

2)利用类加载机制保证线程安全

6.序列化

1)可以利用指定方法来替换从反序列化流中的数据

小结

虽然单例模式只是一个很平常的模式,但在各种的实现上却需要用到Java的基本功,包括懒汉模式、饿汉模式、线程是否安全、静态类、内部类、加锁和串行化等。在日常开发中,我们要根据实际情况去选择其中的一种方式。