Java设计模式(单例设计模式)
2021/9/24 17:40:43
本文主要是介绍Java设计模式(单例设计模式),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
一、饿汉模式/立即加载
二、懒汉模式/延迟加载(线程不安全)
三、懒汉式模式(线程安全)
四、懒汉式模式(DCL双检查锁机制(DCL:double checked locking))
五、静态内部类(最优方法)
单例模式定义:确保某一个类只有一个实例,并且提供一个全局访问点。
单例模式典型3个特点:1、只有一个实例。2、自我实例化。3、提供全局访问点。
一、饿汉模式/立即加载
public class Singleton { // 将自身实例化对象设置为一个属性,并用static、final修饰 private static final Singleton instance = new Singleton(); // 构造方法私有化 private Singleton() {} // 静态方法返回该实例 public static Singleton getInstance() { return instance; } }
优点:实现起来简单,没有多线程同步问题。
缺点:当类Singleton 被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
二、懒汉模式/延迟加载(线程不安全)
public class Singleton { // 将自身实例化对象设置为一个属性,并用static修饰 private static Singleton instance; // 构造方法私有化 private Singleton() {} // 静态方法返回该实例 public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
优点:实现起来比较简单,当类Singleton 被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点:在多线程环境中,不能保证只有一个单例,可能存在多个。
三、懒汉式模式(线程安全)
public class Singleton { // 将自身实例化对象设置为一个属性,并用static修饰 private static Singleton instance; // 构造方法私有化 private Singleton() {} // 静态方法返回该实例,加synchronized关键字实现同步 public static synchronized Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
优点:在多线程情形下,保证了“懒汉模式”的线程安全。
缺点:众所周知在多线程情形下,synchronized方法通常效率低,显然这不是最佳的实现方案。
四、懒汉式模式(DCL双检查锁机制(DCL:double checked locking))
public class Singleton { // 将自身实例化对象设置为一个属性,并用static修饰 private static Singleton instance; // 构造方法私有化 private Singleton() {} // 静态方法返回该实例 public static Singleton getInstance() { // 第一次检查instance是否被实例化出来,如果没有进入if块 if(instance == null) { synchronized (Singleton.class) { // 某个线程取得了类锁,实例化对象前第二次检查instance是否已经被实例化出来,如果没有,才最终实例出对象 if (instance == null) { instance = new Singleton(); } } } return instance; } }
优点:DCL模式的优点就是,只有在对象需要被使用时才创建,第一次判断 instance== null为了避免非必要加锁,当第一次加载时才对实例进行加锁再实例化。这样既可以节约内存空间,又可以保证线程安全。但是,由于jvm存在乱序执行功能,DCL也会出现线程不安全的情况。
INSTANCE = new SingleTon();这个步骤,其实在jvm里面的执行分为三步:
1.在堆内存开辟内存空间。
2.在堆内存中实例化SingleTon里面的各个参数。
3.把对象指向堆内存空间。
由于jvm存在乱序执行功能,所以可能在2还没执行时就先执行了3,如果此时再被切换到线程B上,由于执行了3,INSTANCE 已经非空了,会被直接拿出来用,这样的话,就会出现异常。这个就是著名的DCL失效问题。
不过在JDK1.5之后,官方也发现了这个问题,故而具体化了volatile,即在JDK1.6及以后,只要定义为private volatile static SingleTon INSTANCE = null;就可解决DCL失效问题。volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。
五、静态内部类(最优方法)
public class SingleTon{ private SingleTon(){} private static class SingleTonHoler{ private static SingleTon INSTANCE = new SingleTon(); } public static SingleTon getInstance(){ return SingleTonHoler.INSTANCE; } }
静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
---------------------------------------------------------------------------------------------------------------------------------
参考:
cjava设计模式--单例模式 - 吟啸且徐行 - 博客园
设计模式之单例模式 - chenghaow - 博客园
这篇关于Java设计模式(单例设计模式)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求