02-设计模式——单例模式
设计模式——单例模式
通过
javap -v -p xxxx.class
可以查看对应字节码信息
模式定义
保证一个类只有一个实例,并且提供一个全局访问点
场景:
重量级的对象,不需要多个实例,如线程池,数据库连接池
懒汉模式
1.懒汉模式:延迟加载,只有在真正使用的时候,才开始实例化
- 线程安全问题
- double check 双重检查,加锁优化
- 编译器(JIT),CPU有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排
/**
* @program: DesignPatterns
* @description: 懒汉单例模式
* @author: Coder_Pan
* @create: 2022-04-12 18:48
**/
public class LazySingletonTest {
public static void main(String[] args) {
/**
* 第一个线程开启
*/
new Thread( () -> {
LazySingleton instance = LazySingleton.getInstance();
System.out.println(instance);
}).start();
/**
* 第二个线程开启
*
* 运行会发现两个线程中创建的对象不一致
*
*/
new Thread( () -> {
LazySingleton instance = LazySingleton.getInstance();
System.out.println(instance);
}).start();
/**
* 单个线程下一切ok
*/
// LazySingleton instance = LazySingleton.getInstance();
// LazySingleton instance1 = LazySingleton.getInstance();
// System.out.println(instance == instance1);
}
}
/**
* 创建懒汉实例
*/
class LazySingleton {
/**
* 加上volatile防止重排序,规定字节码层面顺序为123
*/
private volatile static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance() {
/**
* 如果实例为空,才创建
* synchronized =》 加锁,保证只有一个实例
*/
if (instance == null) {
/**
* 当对象为空时才进行加锁
*
* 防止重复加锁操作
*/
synchronized (LazySingleton.class){
if (instance == null) {
instance = new LazySingleton();
//字节码层
//1.分配空间
//2.初始化
//3.引用赋值
}
}
}
return instance;
}
// public synchronized static LazySingleton getInstance() {
// /**
// * 如果实例为空,才创建
// * 需要在LazySingleton的getInstance上加上synchronized才能保持多个线程下实例对象的一致性,这个方式会造成资源浪费,重复加锁
// * synchronized =》 加锁,保证只有一个实例
// */
// if (instance == null) {
//
// instance = new LazySingleton();
// }
// return instance;va
// }
}
饿汉模式
类加载的初始化阶段就完成了实例的初始化。
本质上就是借助与jvm类加载机制,保证实例的唯一性
类加载过程:
- 加载二进制数据到内存中,生成对应的Class数据结构
- 连接:a、验证 ,b、准备(给类的静态成员变量赋默认值),c、解析
- 初始化:给类的静态变量赋初值
只有在真正使用对应的类时,才会触发初始化 如(当前类时启动类,即main函数所在类,直接进行new操作,访问静态属性,访问静态方法,用反射访问类,初始化一个类的子类等)
/**
* @program: DesignPatterns
* @description: 饿汉单例模式
* @author: Coder_Pan
* @create: 2022-04-12 19:32
**/
public class HungrySingletonTest {
public static void main(String[] args) {
System.out.println("饿汉单例模式...HungrySingleton");
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton instance1 = HungrySingleton.getInstance();
System.out.println(instance == instance1);
}
}
/**
* 饿汉模式 ⬇
*/
class HungrySingleton{
/**
* 静态属性在何时实例化
*/
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){
}
/**
* 公开的方法,对外提供访问
* @return
*/
public static HungrySingleton getInstance() {
return instance;
}
}
静态内部类
- 本质上是利用类的加载机制来保证线程安全
- 只有在实际使用的时候,才会触发类的初始化,所有页式懒加载的一种形式
/**
* @program: DesignPatterns
* @description: 静态内部类实现方式
* @author: Coder_Pan
* @create: 2022-04-12 19:56
**/
public class InnerClassSingletonTest {
public static void main(String[] args) {
InnerClassSingleton instance = InnerClassSingleton.getInstance();
InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
System.out.println(instance == instance1);
//创建线程
new Thread( () -> {
InnerClassSingleton instance2 = InnerClassSingleton.getInstance();
System.out.println("Thread - 1" + instance2);
}).start();
new Thread( () -> {
InnerClassSingleton instance2 = InnerClassSingleton.getInstance();
System.out.println("Thread - 2" + instance2);
}).start();
}
}
class InnerClassSingleton{
/**
* InnerClassHolder => 静态内部类
* 基于jvm实现的懒加载模式
*
* 只有在调用getInstance()方法的时候才会导致静态内部类的初始化
* 进而才会使InnerClassSingleton初始化
*/
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
反射攻击
/**
* 反射攻击
*
* 通过反射创建实例,单例模式就失效了
*/
try {
Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
InnerClassSingleton instance = declaredConstructor.newInstance();
InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
System.out.println("反射机制创建单例模式");
System.out.println(instance == instance1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
class InnerClassSingleton{
/**
* InnerClassHolder => 静态内部类
* 基于jvm实现的懒加载模式
*
* 只有在调用getInstance()方法的时候才会导致静态内部类的初始化
* 进而才会使InnerClassSingleton初始化
*/
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
/**
* 防止反射攻击,使单例模式不被破坏
*/
if (InnerClassHolder.instance != null){
throw new RuntimeException(" 单例模式下不允许多个实例! ");
}
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
如果想实现数据的一个持久化的操作,就需要这个类进行序列化,这样jvm才会对其处理
即implements Serializable,开启序列化
源码中的应用
java.lang.Runtime
ProxyFactoryBean
DefaultSingletonBeanRegistry
ReactiveAdapterRegistry
TomcatURLStreamHandlerFactory
//反序列化指定数据源
java.util.Currency
posted on 2022-04-12 21:28 JavaCoderPan 阅读(21) 评论(0) 收藏 举报 来源
浙公网安备 33010602011771号