• 设计模式-单例模式


    目录

    设计模式原则

     一、抽象工厂模式

    1.1 定义

    1.2 类图

    1.3 优点

    1.4 例子

    二、单例模式

    2.1 定义

    2.2 优缺点

    2.3 应用场景

    Runtime.java

    DefaultSingletonBeanRegistry.java

    ReactiveAdapterRegistry.java

    Currency.java

    2.4 实现方式

    1、懒汉模式

    2、恶汉模式

    3、静态内部类

    反射打破单例模式情况


    设计模式原则

    开闭原则 对扩展开放,对修改关闭

    单⼀职责原则 ⼀个类只负责⼀个功能领域中的相应职责

    ⾥⽒替换原则 所有引⽤基类的地⽅必须能透明地使⽤其⼦类的对象

    依赖倒置原则 依赖于抽象,不能依赖于具体实现

    接⼝隔离原则 类之间的依赖关系应该建⽴在最⼩的接⼝上

    合成/聚合复⽤原则 尽量使⽤合成/聚合,⽽不是通过继承达到复⽤的⽬的

    迪⽶特法则 ⼀个软件实体应当尽可能少的与其他实体发⽣相互作⽤

     一、抽象工厂模式

    1.1 定义

    抽象工厂模式(Abstract FactoryPattern)围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂

    1.2 类图

    1.3 优点

    单一职责

    开闭原则 

    1.4 例子

    Connection.java

    二、单例模式

    2.1 定义

    保证一个类只有一个实例,并且提供一个全局访问点

    2.2 优缺点

    优点:一个单例类只存在一个实例,减少开销、避免创建和销毁是对资源的多重占用

    确定:没有抽象层、难以扩展、违反设计模式思想的单一职责原则。

    2.3 应用场景

    线程池、连接池等情况

    Runtime.java

    标准的恶汉模式

    DefaultSingletonBeanRegistry.java

    懒汉模式

    ReactiveAdapterRegistry.java

    volatile的懒汉模式

    Currency.java

    带序列化和反序列化

    2.4 实现方式

    1、懒汉模式

    需要优化:线程安全、双重校验、防止指令重排 voilatile

    为什么要用voilatile?

    因为可见性、防止指令重排,new过程不是原子操作。会经历1、开启堆空间 2、构造方法初始化对象 3、引用变量指向堆内存空间

    1. package com.example.demo.designPattern.singleton;
    2. /**
    3. * @author 10450
    4. * @description 懒汉模式
    5. * 并发情况下,有可能
    6. * @date 2022/9/15 13:58
    7. */
    8. public class LazySingletonTest {
    9. public static void main(String[] args){
    10. new Thread(()->{
    11. LazySingleton intance = LazySingleton.getSingleton();
    12. System.out.println(intance);
    13. }).start();
    14. new Thread(()->{
    15. LazySingleton intance = LazySingleton.getSingleton();
    16. System.out.println(intance);
    17. }).start();
    18. new Thread(()->{
    19. LazySafeSingleton intance = LazySafeSingleton.getSingleton();
    20. System.out.println(intance);
    21. }).start();
    22. new Thread(()->{
    23. LazySafeSingleton intance = LazySafeSingleton.getSingleton();
    24. System.out.println(intance);
    25. }).start();
    26. new Thread(()->{
    27. LazyVolatileSingleton intance = LazyVolatileSingleton.getSingleton();
    28. System.out.println(intance);
    29. }).start();
    30. new Thread(()->{
    31. LazyVolatileSingleton intance = LazyVolatileSingleton.getSingleton();
    32. System.out.println(intance);
    33. }).start();
    34. }
    35. }
    36. /**
    37. * 多线程不安全
    38. */
    39. class LazySingleton{
    40. private static LazySingleton instance;
    41. private LazySingleton(){
    42. }
    43. public static LazySingleton getSingleton(){
    44. if(instance==null){
    45. try{
    46. Thread.sleep(5000);
    47. instance = new LazySingleton();
    48. }catch (InterruptedException e) {
    49. e.printStackTrace();
    50. }
    51. }
    52. return instance;
    53. }
    54. }
    55. /**
    56. * 多线程安全,但是指令重排有问题
    57. */
    58. class LazySafeSingleton{
    59. private static LazySafeSingleton instance;
    60. private LazySafeSingleton(){
    61. }
    62. public static LazySafeSingleton getSingleton(){
    63. if(instance==null){
    64. synchronized (LazySafeSingleton.class){
    65. if(instance==null){
    66. try{
    67. Thread.sleep(5000);
    68. instance = new LazySafeSingleton();
    69. }catch (InterruptedException e) {
    70. e.printStackTrace();
    71. }
    72. }
    73. }
    74. }
    75. return instance;
    76. }
    77. }
    78. /**
    79. * 防止指令重排
    80. */
    81. class LazyVolatileSingleton{
    82. private volatile static LazyVolatileSingleton instance;
    83. private LazyVolatileSingleton(){
    84. }
    85. public static LazyVolatileSingleton getSingleton(){
    86. if(instance==null){
    87. synchronized (LazyVolatileSingleton.class){
    88. if(instance==null){
    89. try{
    90. Thread.sleep(5000);
    91. instance = new LazyVolatileSingleton();
    92. }catch (InterruptedException e) {
    93. e.printStackTrace();
    94. }
    95. }
    96. }
    97. }
    98. return instance;
    99. }
    100. }

    2、恶汉模式

    类加载的初始化节点完成实例初始化。本质就是JVM类加载机制,保证实例唯一性。

    类加载是就创建对象、比较常用,但是容易浪费空间。

    优点:线程安全、没有加锁,执行效率快

    缺点:浪费空间

    类加载过程:

    1. 加载二进制字节码数据到内存中,生成对应class数据结构
    2. 连接:a:验证、b:准备(给类的静态成员变量赋默认值),c:解析
    3. 初始化:给类静态变量赋初值
      1. package com.example.demo.designPattern.singleton;
      2. /**
      3. * @author 10450
      4. * @description 恶汉模式
      5. * 类加载的时候完成初始化
      6. * @date 2022/9/15 14:23
      7. */
      8. public class HungrySingletonTest {
      9. public static void main(String[] args) {
      10. System.out.println(HungrySingleton.getInstance());
      11. System.out.println(HungrySingleton.getInstance());
      12. }
      13. }
      14. class HungrySingleton{
      15. private static HungrySingleton instance = new HungrySingleton();
      16. private HungrySingleton(){
      17. }
      18. public static HungrySingleton getInstance(){
      19. return instance;
      20. }
      21. }

      3、静态内部类

         优点:懒加载,线程安全,效率较⾼,实现简单

    • 本质上利用类的加载机制保证线程安全
    • 只要在实际使用的时候才会触发累的初始化,也是懒加载的一种
      1. package com.example.demo.designPattern.singleton;
      2. import java.lang.reflect.Constructor;
      3. import java.lang.reflect.InvocationTargetException;
      4. /**
      5. * @author 10450
      6. * @description 静态内部类
      7. * 可以防止通过反射,实现多利
      8. * @date 2022/9/15 14:28
      9. */
      10. public class InnerClassSingletonTest {
      11. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
      12. new Thread(()->{
      13. System.out.println(InnerClassSingleton.getInstance());
      14. }).start();
      15. new Thread(()->{
      16. System.out.println(InnerClassSingleton.getInstance());
      17. }).start();
      18. //利用反射方式创建类对象打破单例模式,实现多利
      19. Constructor declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
      20. declaredConstructor.setAccessible(true);
      21. InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();
      22. InnerClassSingleton instance = InnerClassSingleton.getInstance();
      23. System.out.println(innerClassSingleton);
      24. System.out.println(instance);
      25. }
      26. }
      27. class InnerClassSingleton{
      28. private static class InnerClassSingletonHolder{
      29. private static InnerClassSingleton instance = new InnerClassSingleton();
      30. }
      31. private InnerClassSingleton(){
      32. }
      33. public static InnerClassSingleton getInstance(){
      34. try {
      35. System.out.println(1);
      36. Thread.sleep(8000);
      37. System.out.println(2);
      38. } catch (InterruptedException e) {
      39. e.printStackTrace();
      40. }
      41. return InnerClassSingletonHolder.instance;
      42. }
      43. }

      反射打破单例模式情况

    通过反射方式创建类,可以打破单例模式,实现多例效果,

    【恶汉模式】、【内部类模式】可以判断防止多例

    1. package com.example.demo.designPattern.singleton;
    2. import java.lang.reflect.Constructor;
    3. import java.lang.reflect.InvocationTargetException;
    4. /**
    5. * @author 10450
    6. * @description 反射攻击
    7. * @date 2022/9/15 15:03
    8. */
    9. public class InnerClassReflexSingletonTest {
    10. public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    11. //单例保护防止多利情况下:
    12. Constructor declaredConstructor = InnerClassProtectSingleton.class.getDeclaredConstructor();
    13. declaredConstructor.setAccessible(true);
    14. InnerClassProtectSingleton innerClassSingleton = declaredConstructor.newInstance();
    15. InnerClassProtectSingleton instance = InnerClassProtectSingleton.getInstance();
    16. System.out.println(innerClassSingleton);
    17. System.out.println(instance);
    18. }
    19. }
    20. /**
    21. * 防止多例
    22. */
    23. class InnerClassProtectSingleton {
    24. private static class InnerClassSingletonHolder {
    25. private static InnerClassProtectSingleton instance = new InnerClassProtectSingleton();
    26. }
    27. private InnerClassProtectSingleton() {
    28. //添加校验,抛异常
    29. if (InnerClassSingletonHolder.instance != null) {
    30. throw new RuntimeException("单例模式,不运行重复创建");
    31. }
    32. }
    33. public static InnerClassProtectSingleton getInstance() {
    34. return InnerClassProtectSingleton.InnerClassSingletonHolder.instance;
    35. }
    36. }

  • 相关阅读:
    ALL in Boom 日志记录 (ing ...
    《XSS-Labs》01. Level 1~10
    《Docker Compose入门:多容器应用的定义和管理》
    AMD CPU Nvidia GPU Ubuntu 黑屏网络故障案例分享
    LabVIEW 使用VISA Close真的关闭COM口了吗
    01-自动内存管理机制
    淘宝API接口,获取数据
    Vue3从入门到精通(三)
    学习ASP.NET Core Blazor编程系列七——新增图书
    【深度学习入门】- 用电路思想解释感知机
  • 原文地址:https://blog.csdn.net/chenlu4ever/article/details/126869902