当前位置: 首页 > news >正文

单例模式的八种写法、单例和并发的关系

文章目录

  • 1.单例模式的作用
  • 2.单例模式的适用场景
  • 3.饿汉式
    • 静态常量(可用)
    • 静态代码块(可用)
  • 4.懒汉式
    • 线程不安全(不可用)
    • 同步方法(线程安全,但不推荐用)
    • 同步代码块(线程不安全,不可用)
    • 双重检查 + volatile(推荐用)
    • 静态内部类(推荐用)
    • 枚举(推荐用)

1.单例模式的作用

为什么需要单例?

  • 节省内存和计算
  • 保证结果正确
  • 方便管理

2.单例模式的适用场景

  1. 无状态的工具类:比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象即可。
  2. 全局信息类:比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象 A 上,有的却记录在对象 B 上,这时候我们就让这个类成为单例。

3.饿汉式

静态常量(可用)

/*** 饿汉式(静态常量)(可用)*/
public class Singleton1 {// 由于加了static关键字,根据JVM的规定,在类加载的时候就会完成INSTANCE的实例化,这样就避免了线程同步问题private final static Singleton1 INSTANCE = new Singleton1();// 构造函数是私有的private Singleton1() {}public static Singleton1 getInstance() {return INSTANCE;}
}

静态代码块(可用)

/*** 饿汉式(静态代码块)(可用)*/
public class Singleton2 {private final static Singleton2 INSTANCE;// 与上一种写法类似,由JVM保证了线程安全static {INSTANCE = new Singleton2();}// 构造函数是私有的private Singleton2() {}public static Singleton2 getInstance() {return INSTANCE;}
}

4.懒汉式

线程不安全(不可用)

/*** 懒汉式(线程不安全)(不可用)*/
public class Singleton3 {private static Singleton3 instance;// 构造函数是私有的private Singleton3() {}public static Singleton3 getInstance() {// 这种写法是线程不安全的,不可用if (instance == null) {instance = new Singleton3();}return instance;}
}

同步方法(线程安全,但不推荐用)

/*** 懒汉式(线程安全)(不推荐用)*/
public class Singleton4 {private static Singleton4 instance;// 构造函数是私有的private Singleton4() {}// 这种写法虽然是线程安全的,但是效率太低,不推荐用public synchronized static Singleton4 getInstance() {if (instance == null) {instance = new Singleton4();}return instance;}
}

同步代码块(线程不安全,不可用)

/*** 懒汉式(线程不安全)(不可用)*/
public class Singleton5 {private static Singleton5 instance;// 构造函数是私有的private Singleton5() {}public static Singleton5 getInstance() {// 这种写法并不是线程安全的,不可用if (instance == null) {synchronized (Singleton5.class) {instance = new Singleton5();}}return instance;}
}

双重检查 + volatile(推荐用)

优点:线程安全,延迟加载,效率较高。

/*** 双重检查 + volatile(推荐用)*/
public class Singleton6 {// volatile防止重排序private volatile static Singleton6 instance;// 构造函数是私有的private Singleton6() {}public static Singleton6 getInstance() {// 双重检查保证线程安全if (instance == null) {synchronized (Singleton6.class) {if (instance == null) {instance = new Singleton6();}}}return instance;}
}

为什么要用 volatile?

新建对象 rs = new Resource() 实际上有 3 个步骤:

  • construct empty resource()
  • call constructor
  • assign to rs

如下图所示,重排序会带来NPE问题(NullPointerException, 空指针异常),而使用 volatile 可以防止重排序。

在这里插入图片描述

静态内部类(推荐用)

/*** 静态内部类(线程安全,懒加载)(推荐用)*/
public class Singleton7 {// 构造函数是私有的private Singleton7() {}// 由JVM的规定可知,这种写法同时满足了线程安全和懒加载两个优点private static class SingletonInstance {private static final Singleton7 INSTANCE = new Singleton7();}public static Singleton7 getInstance() {return SingletonInstance.INSTANCE;}
}

枚举(推荐用)

单例模式的书写:

/*** 枚举(线程安全,懒加载)(推荐用)*/
public enum Singleton8 {INSTANCE;public void whatever() {}
}

单例的使用:

Singleton8.INSTANCE.whatever();

哪种单例的实现方案最好?

Joshua Bloch 大神在《Effective Java》中明确表达过的观点:使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经成为实现 Singleton 的最佳方法。

  • 写法简单
  • 线程安全有保障
  • 懒加载
  • 避免反序列化破坏单例

相关文章:

  • 打印日期c++
  • Java获取文件的后缀名称
  • netcore html to pdf
  • 代码随想录算法训练营第32天|122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II
  • 基于反卷积方法的重大突破:结构光系统中的测量误差降低3倍
  • 设计模式之并发特定场景下的设计模式 Two-phase Termination(两阶段终止)模式
  • Linux中常使用的命令之ls、cd、pwd、mkdir、rmdir
  • 数字后端设计实现之自动化useful skew技术(Concurrent Clock Data)
  • Linux - No space left on device
  • 后端程序员开发win小工具(未完待续)
  • JS浏览器的默认行为及阻止行为,阻止右键菜单、阻止超链接跳转、阻止拖拽事件
  • k8s的yaml文件中的kind类型都有哪些?(详述版Part1/2)
  • C#高级 10 Linq操作
  • 记mongodb7.0安装时的常用操作 windows
  • Docker容器进入的4种方式(推荐最后一种)
  • php的引用
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 78. Subsets
  • CSS 提示工具(Tooltip)
  • go append函数以及写入
  • js作用域和this的理解
  • nodejs:开发并发布一个nodejs包
  • Unix命令
  • vue--为什么data属性必须是一个函数
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 二维平面内的碰撞检测【一】
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 前端攻城师
  • 前端知识点整理(待续)
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 如何设计一个比特币钱包服务
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 阿里云服务器购买完整流程
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​Java并发新构件之Exchanger
  • #HarmonyOS:基础语法
  • #单片机(TB6600驱动42步进电机)
  • #微信小程序:微信小程序常见的配置传值
  • (27)4.8 习题课
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (zhuan) 一些RL的文献(及笔记)
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (转)视频码率,帧率和分辨率的联系与区别
  • (转)一些感悟
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET CF命令行调试器MDbg入门(一)
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .NET框架设计—常被忽视的C#设计技巧
  • ??myeclipse+tomcat