Java23种设计模式-创建型模式之单例模式

ops/2024/9/23 11:12:52/

单例模式(Singleton Pattern):通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例),该类负责创建自己的对象,同时确保只有单个对象被创建。

1、单例类只能一个实例
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

Java中两种构建方式:
懒汉式线程不安全:最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加synchronize之类的锁,以提高性能。这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作
懒汉式线程安全加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很低,大部分时间并不需要同步饿汉方式。指全局的单例实例在类装载时构建。
饿汉式:这种方式比较常用,但容易产生垃圾对象。优点:没有加锁,执行效率会提高。缺点:类加载时就初始化,浪费内存。基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果
双检锁/双重校验锁(DCL,即 double-checked locking):在懒汉式基础上利用synchronize关键字和volatile关键字确保第一次创建时没有线程间竞争而产生多个实例,仅第一次创建时同步,性能相对较高。
登记式/静态内部类:作为创建类的全局属性存在,创建类被装载时创建。
枚举:java中枚举类本身也是一种单例模式

应用场景包括需要控制实例数量的类,如数据库连接池配置管理日志记录等。单例模式的主要优点包括防止多次实例化节省资源提供全局访问点以及减少全局状态的复杂性。然而,它也有一些缺点,比如可能导致代码难以测试和维护,以及在多线程环境中可能存在线程安全问题

单例模式的实现通常包括将构造方法设置为私有,以防止外部代码创建实例。它还可能包括一个私有的静态实例成员以及一个公共的静态方法用于获取这个实例。此外,双重检查锁定(double-checked locking)是一种常用的实现线程安全单例的方法。

示例

//懒汉式,线程不安全
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 Singleton instance;public Singleton() {}public static synchronized Singleton getInstance(){if (instance==null){instance=new Singleton();}return instance;}
}
//饿汉式 线程安全
public class Singleton {private static Singleton instance=new Singleton();public Singleton() {}public static Singleton getInstance(){return instance;}
}
//双检锁/双重校验锁(DCL,即 double-checked locking)
public class Singleton {private volatile static Singleton singleton;public Singleton() {}public static Singleton getSingleton(){if (singleton==null){synchronized (Singleton.class){if (singleton==null){singleton=new Singleton();}}}return singleton;}
}//登记式/静态内部类
public class Singleton {private static class SingletonHolder{private static final Singleton INSTANCE=new Singleton();}public Singleton() {}public static final Singleton getInstance(){return SingletonHolder.INSTANCE;}
}
//枚举
public enum Singleton {INSTANCE;public void test(){System.out.println("hi~");}
}
//CAS「AtomicReference」(线程安全)
public class Singleton {private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();private Singleton() {}public static final Singleton getInstance() {for (; ; ) {Singleton instance = INSTANCE.get();if (null != instance) return instance;INSTANCE.compareAndSet(null, new Singleton());return INSTANCE.get();}}public static void main(String[] args) {System.out.println(Singleton.getInstance()); System.out.println(Singleton.getInstance()); }
}

一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式

增加:CAS「AtomicReference」(线程安全)
java并发库提供了很多原子类来支持并发访问的数据安全性;AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference。
AtomicReference 可以封装引用一个V实例,支持并发访问如上的单例方式就是使用了这样的一个特点。
使用CAS的好处就是不需要使用传统的加锁方式保证线程安全,而是依赖于CAS的忙等算法,依赖于底层硬件的实现,来保证线程安全。相对于其他锁的实现没有线程的切换和阻塞也就没有了额外的开销,并且可以支持较大的并发性。
当然CAS也有一个缺点就是忙等,如果一直没有获取到将会处于死循环中。


http://www.ppmy.cn/ops/21895.html

相关文章

Matlab新手快速上手2(粒子群算法)

本文根据一个较为简单的粒子群算法框架详细分析粒子群算法的实现过程&#xff0c;对matlab新手友好&#xff0c;源码在文末给出。 粒子群算法简介 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;是一种群体智能优化算法&#xff0c;灵感来源于…

Docker镜像和容器操作

目录 一.Docker镜像创建与操作 1. 搜索镜像 2. 获取镜像 3. 镜像加速下载 4. 查看镜像信息 5. 查看下载的镜像文件信息 ​编辑6. 查看下载到本地的所有镜像 7. 根据镜像的唯一标识ID号&#xff0c;获取镜像详细信息 8. 为本地的镜像添加新的标签 9. 删除镜像 10. 存入…

数据库之数据库恢复技术思维导图+大纲笔记

大纲笔记&#xff1a; 事务的基本概念 事务 定义 用户定义的一个数据库操作系列&#xff0c;这些操作要么全做&#xff0c;要么全不做&#xff0c;是一个不可分割的基本单位 语句 BEGIN TRANSACTION 开始 COMMIT 提交&#xff0c;提交事务的所有操作 ROLLBACK 回滚&#xff0c…

CUDA的基础知识

文章目录 数据精度CUDA概念线程&线程块&线程网络&计算核心GPU规格参数内存 GPU并行方式数据并行流水并行张量并行混合专家系统 数据精度 FP32 是单精度浮点数&#xff0c;用8bit 表示指数&#xff0c;23bit 表示小数&#xff1b;FP16 是半精度浮点数&#xff0c;用…

PlayerSettings.WebGL.emscriptenArgs设置无效的问题

1&#xff09;PlayerSettings.WebGL.emscriptenArgs设置无效的问题 2&#xff09;java.lang.NoSuchMethodError的不明崩溃问题 3&#xff09;UE电影摄像机旋转问题 4&#xff09;Android设备游戏切后台后唤起&#xff0c;有概率变卡且黑屏 这是第383篇UWA技术知识分享的推送&am…

MATLAB使用速成 第七章(多项式运算与代数方程求解)

一、多项式运算 1、多项式的表示方法 &#xff08;1&#xff09;在MATLAB中&#xff0c;n次多项式用一个长度为n1的向量来表示。 &#xff08;2&#xff09;多项式与符号表达式的互化&#xff1a; ①语句“poly2sym(x)”可将多项式x转化为符号表达式。 ②语句“sym2poly(f)…

c++继承

目录 前言 继承的概念及定义 继承方式与访问限定符 基类和派生类对象赋值转换 隐藏的概念 派生类的默认成员函数 派生类的构造函数 派生类的赋值重载 派生类的析构函数 继承之友元与静态成员 菱形继承及菱形虚继承 单继承 多继承 菱形继承 虚继承原理 继承与组合…

Spring AOP

Session 认证和 Token 认证 过滤器和拦截器 基于Token认证的登录功能实现 SpringBoot统一返回和统一异常处理 SpringBoot项目logback日志配置 Spring事务 Spring AOP AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程&#xff09;&#xff1a;核心…