几种场景的单例模式思考总结(饿汉、懒汉、线程安全懒汉、反射破坏、反序列化破坏)

本文主要是介绍几种场景的单例模式思考总结(饿汉、懒汉、线程安全懒汉、反射破坏、反序列化破坏),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天先直接上代码,后续在补充一下单例模式的定义。。

饿汉式单例模式(线程安全):

public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

懒汉式单例模式(非线程安全):

public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

懒汉式单例模式(线程安全,双重检查锁定):

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

反射破坏单例(非线程安全):

其中反射破坏单例是指通过反射机制,可以绕过单例模式的控制,从而在单例类的构造方法中多次创建实例,破坏了单例模式的设计意图。

所以通过在单例类的构造方法中增加判断,如果已经存在实例,则抛出异常或返回已存在的实例。

public class Singleton {private static Singleton instance;private Singleton() {if (instance != null) {throw new RuntimeException("Cannot instantiate singleton class using reflection");}}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

反序列化破坏单例(线程安全):

反序列化破坏单例是指在使用序列化和反序列化机制时,可能会破坏单例模式的设计。Java 的序列化机制允许将对象转换为字节序列,以便于存储或传输,而反序列化则是将字节序列还原为对象。
**在单例类中增加 readResolve() 方法是为了在对象反序列化时返回同一实例,从而保证单例的唯一性。**这样可以防止在反序列化时创建多个实例,保持了单例模式的设计意图。
在给定的代码中,readResolve() 方法返回的是单例类的静态实例 instance,这意味着无论在何种情况下反序列化该对象,都将返回同一个实例。这样可以确保反序列化的对象与已存在的单例实例相同,避免了创建新的实例,从而保持了单例的唯一性。
需要注意的是,readResolve() 方法的访问控制符应该是 private,以确保只有单例类本身可以调用该方法,防止在外部通过反射等方式调用。

import java.io.Serializable;public class Singleton implements Serializable {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}// 在反序列化过程中,readResolve() 方法会在对象反序列化时被调用,直接返回单例实例,确保单例的唯一性。protected Object readResolve() {return instance;}
}

这篇关于几种场景的单例模式思考总结(饿汉、懒汉、线程安全懒汉、反射破坏、反序列化破坏)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/867624

相关文章

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点:

Java通过反射获取方法参数名的方式小结

《Java通过反射获取方法参数名的方式小结》这篇文章主要为大家详细介绍了Java如何通过反射获取方法参数名的方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、解决方式方式2.1: 添加编译参数配置 -parameters方式2.2: 使用Spring的内部工具类 -

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例