【设计模式-01】Singleton单利模式

一、方式1(最常用,推荐使用)

单例实现方式一: 饿汉式

类加载到内存后,就实例化一个单例,JVM保证线程安全

简单实用,推荐使用。

唯一缺点: 不管用到与否,类装载时就完成加载。

/**
 * @description: 单例实现方式一: 饿汉式 <br>
 *     类加载到内存后,就实例化一个单例,JVM保证线程安全 <br>
 *     简单实用,推荐使用。<br>
 *     唯一缺点: 不管用到与否,类装载时就完成加载。
 * @author: flygo
 * @time: 2022/5/27 22:17
 */
public class SingletonManager01 {

  private static final SingletonManager01 INSTANCE = new SingletonManager01();

  private SingletonManager01() {}

  public static SingletonManager01 getInstance() {
    return INSTANCE;
  }

  public static void main(String[] args) {
    SingletonManager01 singletonManager01 = SingletonManager01.getInstance();
    SingletonManager01 singletonManager011 = SingletonManager01.getInstance();

    System.out.println(singletonManager01 == singletonManager011);
  }
}

二、方式2

静态语句块,和方式一一样

/**
 * @description: 同第一种方式一样,静态语句块实现
 * @author: flygo
 * @time: 2022/5/27 22:24
 */
public class SingletonManager02 {

  private static final SingletonManager02 INSTANCE;

  private SingletonManager02() {}

  static {
    INSTANCE = new SingletonManager02();
  }

  public static SingletonManager02 getInstance() {
    return INSTANCE;
  }

  public static void main(String[] args) {
    SingletonManager02 singletonManager02 = SingletonManager02.getInstance();
    SingletonManager02 singletonManager021 = SingletonManager02.getInstance();

    System.out.println(singletonManager02 == singletonManager021);
  }
}

三、方式3(多线程有问题)

懒汉式,虽然达到了按需初始化的目的,但带来了线程不安全的问题

/**
 * @description: lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager03 {
  public static SingletonManager03 INSTANCE;

  private SingletonManager03() {}

  public static SingletonManager03 getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new SingletonManager03();
    }

    return INSTANCE;
  }

  public static void main(String[] args) {
    SingletonManager03 instance1 = SingletonManager03.getInstance();
    SingletonManager03 instance2 = SingletonManager03.getInstance();

    System.out.println(instance1 == instance2);
  }
}
  • 验证这种方式的问题,模拟多线程模式,分析这种方式的问题

线程1执行到 instance == null时,这时实例还没实例化,线程2也刚好执行到instance == null,线程1和线程2初始化了两个不同实例对象。

为把问题模拟的更明显,在初始化之前,休眠1毫秒,模拟线程被打断,初始化不同的实例,效果更明显。

/**
 * @description: lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager03 {
  public static SingletonManager03 INSTANCE;

  private SingletonManager03() {}

  public static SingletonManager03 getInstance() {
    if (INSTANCE == null) {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      INSTANCE = new SingletonManager03();
    }

    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager03.getInstance().hashCode());
              })
          .start();
    }
  }
}

四、方式4

lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题

通过synchronized加锁的方式解决,同时效率下降了

/**
 * @description: lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题 <br>
 *     通过synchronized加锁的方式解决,同时效率下降了
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager04 {
  public static SingletonManager04 INSTANCE;

  private SingletonManager04() {}

  public static synchronized SingletonManager04 getInstance() {
    if (INSTANCE == null) {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      INSTANCE = new SingletonManager04();
    }

    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager04.getInstance().hashCode());
              })
          .start();
    }
  }
}

五、方式5(多线程有问题)

妄图通过减少同步代码块的方式提供效率,然后并不行。相当于没有加锁

/**
 * @description: lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题 <br>
 *     通过synchronized加锁的方式解决,同时效率下降了
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager05 {
  public static SingletonManager05 INSTANCE;

  private SingletonManager05() {}

  public static SingletonManager05 getInstance() {
    if (INSTANCE == null) {
      // 妄图通过减少同步代码块的方式提供效率,然后并不行
      synchronized (SingletonManager05.class) {
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        INSTANCE = new SingletonManager05();
      }
    }

    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager05.getInstance().hashCode());
              })
          .start();
    }
  }
}

六、方式6

使用双重检查

/**
 * @description: lazy loading 懒汉式加载,虽然达到了按需加载的目的,但带来了线程不安全的问题 <br>
 *     通过synchronized加锁的方式解决,同时效率下降了,增加双重检查
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager06 {
  // 需要加volatile,指令重排问题
  public static volatile SingletonManager06 INSTANCE;

  private SingletonManager06() {}

  public static SingletonManager06 getInstance() {
    if (INSTANCE == null) {
      // 双重检查
      synchronized (SingletonManager06.class) {
        if (INSTANCE == null) {
          try {
            Thread.sleep(1);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          INSTANCE = new SingletonManager06();
        }
      }
    }

    return INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager06.getInstance().hashCode());
              })
          .start();
    }
  }
}

七、方式7(完美的方式之一)

静态内部类的方式

JVM保证单例,加载外部类时,不会加载内部类,这样可以实现懒加载

/**
 * @description: 静态内部类的方式 <br>
 *     JVM保证单例,加载外部类时,不会加载内部类,这样可以实现懒加载
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public class SingletonManager07 {

  private SingletonManager07() {}

  private static final class SingletonManager07Holder {
    private static final SingletonManager07 INSTANCE = new SingletonManager07();
  }

  public static SingletonManager07 getInstance() {
    return SingletonManager07Holder.INSTANCE;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager07.getInstance().hashCode());
              })
          .start();
    }
  }
}

八、方式8(完美中的完美)

不仅可以解决多线程同步,还可以解决反序列化问题

/**
 * @description: 不仅可以解决多线程同步,还可以解决反序列化问题 <br>
 * @author: flygo
 * @time: 2022/7/4 09:32
 */
public enum SingletonManager08 {
  INSTANCE;

  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      new Thread(
              () -> {
                System.out.println(SingletonManager08.INSTANCE.hashCode());
              })
          .start();
    }
  }
}

九、源码地址

GitHub - jxaufang168/Design-Patterns: 设计模式学习设计模式学习. Contribute to jxaufang168/Design-Patterns development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/jxaufang168/Design-Patterns


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/302925.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python之Selenium自动化浏览器测试详解

Python之Selenium(自动化浏览器测试) 1.安装selenium 1 pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple 2.下载对应版本的浏览器驱动 CNPM Binaries Mirror 这是我的。 把解压后的驱动放在自己的python.exe 目录下。 3.测试code&#xff0c;打开一个网页…

大甩卖——代码全家桶!!!

Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Python轴承故障诊断 (一)短时傅里叶变换STFT Python轴承故障诊断 (二)连续小波变换CWT_pyts 小波变换 故障-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD_轴承诊断 pytorch-CSDN博客 Pytorch-…

四 视图

1、实验目的 理解SQL成熟设计基本规范&#xff0c;能够熟练使用SQL语句来创建需要的视图&#xff0c;定义数据库外模式&#xff0c;并能使用所创建的视图实现数据管理。 2、实验内容及要求 使用SQL对数据库进行各类查询数据操纵操作&#xff0c;掌握单行数据插入、多行数据插…

开发小技巧 - 合理使用Visual Studio 2022内置任务列表(TODO)

前言 在开发编码过程中经常会因为各种问题而打断自己的思绪和开发计划&#xff0c;可能会导致本来准备开发或者需要测试的功能到要上线的时候才想起来没有做完。这种情况相信很多同学都遇到过&#xff0c;咱们强大的Visual Studio内置了一个任务列表&#xff08;TODO&#xff…

NVIDIA深入理解之pynvml库

一、前言 写在前面 该文章是对我之前文章《Fedora上安装NVIDIA闭源显卡驱动》的一个拓展&#xff0c;正好寒假闲的没事干不如加深一下对NVIDIA的了解。Python是当前非常流行的一门编程语言&#xff0c;它以kiss为设计思想&#xff0c;能封装就能封装&#xff0c;给用户提供比…

Tmux 使用小记

本文参考自 阮一峰老师Tmux 使用教程[1] Tmux,不仅仅是分屏那么简单。。。 与tmux类似的工具是screen 会话管理 将窗口与会话"解绑" 对于没有图形界面只有shell的场景(如服务器)&#xff0c;尤其有用..这是其最核心解决的问题(窗口管理啥的只能算锦上添花的辅助功能)…

想要成为机器学习领域的高手吗?这里有五本必读免费书,订阅周报发链接 (下)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

腾讯云com域名注册1元一年,非常可以!

腾讯云com域名注册优惠价格1元首年&#xff0c;条件是企业新用户&#xff0c;个人新用户注册com域名是33元首年&#xff0c;第二年续费价格85元一年。活动 txybk.com/go/domain-sales 活动打开如下图&#xff1a; 腾讯云com域名注册优惠价格 腾讯云com域名注册原价是85元一年&a…

2024年数学建模美赛能用chatGPT之类的AI吗?官方给了明确规定!

这两年chatGPT等大语言模型火了&#xff0c;能对话&#xff0c;自然也能回答数学建模方面的问题。 那美赛能不能用这些AI呢&#xff1f;2024年美赛官方对chatGPT等的使用做出了明确的规定&#xff08;其中的VI. Contest Instructions部分&#xff09;&#xff1a; https://ww…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票创建页面实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

程序猿的时间管理和生产力

文章目录 为什么时间管理很重要&#xff1f;如何管理时间&#xff1f;心理维度生理维度技术尺寸 时间管理技巧每周计划基于目标的规划番茄钟为什么是25分钟&#xff1f;番茄钟为什么有效&#xff1f;艾森豪威尔矩阵这一切都是从开发者的角度来看的 也许我从开始学习或从事软件开…

企鹅目标检测数据集VOC格式400张

企鹅&#xff0c;一种可爱而独特的鸟类&#xff0c;以其圆滚滚的身体、黑白相间的羽毛和独特的行走方式而备受人们喜爱。 企鹅是鸟纲、企鹅科的动物&#xff0c;它们生活在南半球&#xff0c;特别是南极地区。企鹅的体型短而肥胖&#xff0c;有着流线型的身体和黑白相间的羽毛…

支持API文档生成,API管理工具:Apipost

随着数字化转型的加速&#xff0c;API&#xff08;应用程序接口&#xff09;已经成为企业间沟通和数据交换的关键。而在API开发和管理过程中&#xff0c;API文档、调试、Mock和测试的协作显得尤为重要。Apipost正是这样一款一体化协作平台&#xff0c;旨在解决这些问题&#xf…

条款19:设计class犹如设计type

设计class时&#xff0c;都要面对如下问题&#xff0c;答案通常会导致你的设计规范&#xff1a; 如何创建和销毁新类型的对象&#xff1f;这将影响 类的构造函数和析构函数的设计 内存分配和释放函数的设计 (operator new, operator new[], operator delete, operator delete[…

CSS基础选择器

1.CSS选择器&#xff08;重点&#xff09; 理解 能说出选择器的作用 id选择器和类选择器的区别 应用 能够使用基础选择器给页面元素添加样式 如图所以&#xff0c;要把里面的小黄人分为2组&#xff0c;最快的方法怎办&#xff1f; 1.1 选择器的作用 找到特定的HTML页面元…

金蝶EAS pdfviewlocal.jsp接口存在任意文件读取漏洞 附POC软件

免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. 金蝶EAS简介 微信公众号搜索:南风漏洞复现文库 该…

分布式「走进分布式一致性协议」从2PC、3PC、Paxos 到 ZAB

设计一个分布式系统必定会遇到一个问题—— 因为分区容忍性&#xff08;partition tolerance&#xff09;的存在&#xff0c;就必定要求我们需要在系统可用性&#xff08;availability&#xff09;和数据一致性&#xff08;consistency&#xff09;中做出权衡 。这就是著名的 C…

跨平台的传输协议@WebDav协议@windows系统配置WedDav服务器@局域网内的WebDav传输系统

文章目录 WebDav协议基本信息启用必要的windows功能启动站点管理器IIS站点根目录访问权限设置站点的功能设置端口通行防火墙IMME文件类型(文件后缀)其他设备登录和访问本机的WebDav服务站点 小结优点缺点 refs WebDav 协议基本信息 来自wikipedia:基于Web的分布式编写和版本控…

【Linux】Linux系统编程——Linux命令解析器

【Linux】Linux系统编程——Linux命令解析器 什么是Linux 命令解析器&#xff1f; Linux 命令解析器&#xff0c;通常被称为 shell&#xff0c;是 Linux 操作系统中的一个关键组件。它充当用户和系统内核之间的接口&#xff0c;允许用户通过输入命令来控制和管理操作系统和应…