六、设计模式-6.1、单例模式

devtools/2024/10/18 16:55:16/

6.1、单例模式

6.1.1、在Java中实现单例模式有哪些方法?

答:
在Java中,实现单例模式的常用方法有以下几种:

  1. 饿汉式单例模式:在类加载时就创建一个实例,并提供一个公共的静态方法获取实例。代码示例:
java">public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
  1. 懒汉式单例模式(线程安全):在第一次调用获取实例的方法时创建实例,保证只有一个实例被创建。代码示例:
java">public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
  1. 懒汉式单例模式(双重检查锁定):使用双重检查锁定来保证线程安全和性能。代码示例:
java">public class Singleton {private volatile static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
  1. 静态内部类单例模式(线程安全):利用类加载的特性实现线程安全的懒加载。代码示例:
java">public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton instance = new Singleton();}public static Singleton getInstance() {return SingletonHolder.instance;}
}
  1. 枚举单例模式:使用枚举类型来实现单例模式,枚举类型的实例只能被实例化一次。代码示例:
java">public enum Singleton {INSTANCE;// 可以添加其他方法和属性
}

6.1.2、哪些情况下的单例对象可能会被破坏?

答:

  1. 多线程环境下的并发访问:如果多个线程同时调用getInstance()方法,可能会导致创建多个实例。
  2. 反射:通过反射机制可以访问私有构造方法,从而创建多个实例。
  3. 序列化和反序列化:如果单例类实现了Serializable接口,那么对象可以被序列化和反序列化,从而创建多个实例。
  4. 类加载器的不同:如果使用不同的类加载器加载同一个单例类,会创建多个实例。

6.1.3、在DCL单例写法中,为什么主要做两次检查?

答:
在DCL(Double-Checked Locking)单例写法中,主要进行两次检查是为了在高并发环境下确保线程安全性。假设只进行一次检查,那么在多线程环境下,可能会出现多个线程同时通过第一次检查,然后同时进入同步代码块,创建多个实例对象。

通过进行两次检查,可以避免这种情况发生。第一次检查主要是为了避免不必要的同步开销,只有当实例对象为空时,才需要进一步进行同步。第二次检查主要是为了避免在一个线程创建完实例对象后,另一个线程在获取锁之前进入同步代码块,从而避免重复创建实例对象。

因此,通过进行两次检查,可以在高并发环境下保证只有一个线程能够创建实例对象,从而实现线程安全的单例模式

6.1.4、哪些情景不适合使用单例模式

答:

  1. 需要使用多个不同实例的情景:单例模式只能创建一个实例,如果需要使用多个不同实例,就不适合使用单例模式

  2. 对象的生命周期需要动态控制的情景:单例模式创建的实例一般在程序启动时就被创建,而且在整个程序运行期间都存在。如果需要根据运行时的条件来创建和销毁对象,或者需要在程序的不同阶段创建不同的实例,就不适合使用单例模式

  3. 需要并发创建多个实例的情景:在多线程环境下,如果多个线程需要并发地创建多个实例,就不适合使用单例模式,因为单例模式只能创建一个实例。

  4. 对象依赖外部状态的情景:如果单例对象依赖外部状态,而且在不同的情况下需要使用不同的外部状态,就不适合使用单例模式。因为单例模式只能创建一个实例,无法根据外部状态的变化来动态地改变对象的行为。

6.1.5、哪些情形适合使用单例模式

答:

  1. 需要确保系统中只有一个实例存在的情形:某些资源只能被一个实例使用,例如数据库连接池、线程池等。
java">示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolSingleton {private static ExecutorService instance;private ThreadPoolSingleton() {// 私有构造函数,防止外部创建实例}public static ExecutorService getInstance() {if (instance == null) {synchronized (ThreadPoolSingleton.class) {if (instance == null) {instance = Executors.newFixedThreadPool(10);}}}return instance;}
}
上述代码使用双重检查锁定(Double-Checked Locking)来确保线程安全。
在getInstance方法中,首先进行一次检查,如果实例已经被创建了,则直接返回实例。
如果实例还未被创建,则获取锁,并再次检查实例是否已经被创建。
如果实例仍未被创建,则创建一个新的线程池实例,并将其赋值给instance变量。
这样,通过getInstance方法获取到的线程池对象始终是同一个实例,确保了线程池的单例性。
  1. 需要提供一个全局访问点来访问唯一实例的情形:在整个系统中需要共享某个对象的实例,例如日志记录器、配置文件管理器等。

  2. 需要频繁创建和销毁相同对象的情形:由于创建和销毁对象的开销较大,使用单例模式可以减少对象的创建和销毁次数,提高性能。

  3. 需要用于替代全局变量的情形:全局变量容易被滥用,而单例模式可以提供一个更优雅的方式来管理全局状态。

总的来说,适合使用单例模式的情形是在需要确保只有一个实例存在、需要共享某个实例以及减少对象创建和销毁次数的情况下。


http://www.ppmy.cn/devtools/117875.html

相关文章

Webpack、Rollup、Parcel 和 Grunt、Gulp 的区别

简要描述 Webpack、Rollup 和 Parcel 是前端开发中常用的构建工具,它们各自有不同的特点和适用场景。简要概述如下: 1)Webpack:功能强大、灵活,适合大型项目。支持模块热替换、代码拆分、加载各种类型资源等&#xf…

map的使用

pair类型介绍 map底层的红⿊树节点中的数据&#xff0c;使⽤pair<Key, T>存储键值对数据 typedef pair<const Key, T> value_type; template <class T1, class T2> struct pair {typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair() : …

解决在Nignx下Thinkphp路由不生效问题

Nignx下Tp框架路由不生效 问题的原因在于ThinkPHP通过URL后缀匹配方法&#xff0c;默认没有后缀会尝试访问默认的index方法。 解决方案&#xff1a;在URL末尾添加/后缀或者修改路由配置文件route.php中的规则。 如果还是没解决建议换apache

uniapp自定义Tabbar教程

uniapp自定义Tabbar 1、定义tabbar 在pages.json中配置除主要页面地址&#xff0c; "tabBar": {"custom": true,"list": [{"pagePath": "pages/home/index"},{"pagePath": "pages/user-center/index"…

使用 Vite 打包工具库并使用 GitHub Actions 自动化发布npm流程

使用 Vite 打包一个 TypeScript 编写的 utils 工具库&#xff0c;并在发布到 npm 之前使用 Vitest 进行测试&#xff0c;同时利用 GitHub Actions 自动化发布流程 前言 我们在日常开发中经常会使用 npm install 安装别人的包&#xff0c;使用别人的插件。 当你在前端开发有一…

python判断文件内容是否为空

获取文件大小&#xff0c;如果文件大小等于0就是空的&#xff0c;如下&#xff1a; import os size os.path.getsize(d:/abc.txt) if size 0:print(文件是空的) else:print(文件不是空的)

华为HarmonyOS灵活高效的消息推送服务(Push Kit) - 1 简介

Push Kit&#xff08;推送服务&#xff09;是华为提供的消息推送平台&#xff0c;建立了从云端到终端的消息推送通道。所有HarmonyOS应用可通过集成Push Kit&#xff0c;实现向应用实时推送消息&#xff0c;使消息易见&#xff0c;构筑良好的用户关系&#xff0c;提升用户的感知…

K8s Calico替换为Cilium,以及安装Cilium过程(鲁莽版)

迁移CNI插件的3种办法&#xff1a; 1、创建一个新的集群&#xff0c;通过Gitops的方式迁移负载&#xff0c;然而&#xff0c;这可能涉及大量的准备工作和潜在的中断。 2、另一种方法是重新配置/etc/cni/net.d/指向Cilium。但是&#xff0c;现有的pod仍将由旧的…