006单例模式
创始人
2025-05-29 08:42:18
0

目录

      • what 是单例
      • how 定义
      • why 需要它
      • how 实现
        • 一、懒汉式
        • 二、饿汉式
        • 三、静态方法
        • 四、枚举
        • why 有时候不使用单例类会不会更好

what 是单例

保证一个类只允许创建一个对象 ,这个类就是单例类,这中设计模式就叫单例模式。

how 定义

  • 构造方法私有,避免外部访问
  • 创建对象的安全问题考虑
  • 是否支持延迟加载
  • 考虑 getinstance的性能是否合适

why 需要它

  • 处理资源访问冲突

比如一个打印日志的例子,2个人都new一个日志对象,同时打印一个问题,如果超过一个对象,行为不正确


public class Logger {private FileWriter writer;public Logger() {File file = new File("/Users/wangzheng/log.txt");writer = new FileWriter(file, true); //true表示追加写入}//这里同时调用,会导致日志错乱,可能存在日志信息互相覆盖的情况。public void log(String message) {writer.write(message);}
}// Logger类的应用示例:
public class UserController {private Logger logger = new Logger();public void login(String username, String password) {// ...省略业务逻辑代码...logger.log(username + " logined!");}
}public class OrderController {private Logger logger = new Logger();public void create(OrderVo order) {// ...省略业务逻辑代码...logger.log("Created an order: " + order.toString());}
}
  • 表示全局唯一

比如,项目中配置文件,一个项目只需要有一份就可以了,不需要每次用到还有创建它。或者 ,唯一递增 ID 号码生成 ,如果有2个对象,还存在重复生成id情况 、或者数据库连接池


import java.util.concurrent.atomic.AtomicLong;
public class IdGenerator {// AtomicLong是一个Java并发库中提供的一个原子变量类型,// 它将一些线程不安全需要加锁的复合操作封装为了线程安全的原子操作,// 比如下面会用到的incrementAndGet().private AtomicLong id = new AtomicLong(0);private static final IdGenerator instance = new IdGenerator();private IdGenerator() {}public static IdGenerator getInstance() {return instance;}public long getId() { return id.incrementAndGet();}
}// IdGenerator使用举例
long id = IdGenerator.getInstance().getId();

how 实现

一、懒汉式

饿汉式的实现方式,在类加载的期间,就已经将 instance 静态实例初始化好了,所以,instance 实例的创建是线程安全的。不过,这样的实现方式不支持延迟加载实例。

对于一些创建对象比较耗时,建议使用懒汉式,在程序启动时尽早创建对象,也可以暴露问题


public class IdGenerator { private AtomicLong id = new AtomicLong(0);private static final IdGenerator instance = new IdGenerator();private IdGenerator() {}public static IdGenerator getInstance() {return instance;}public long getId() { return id.incrementAndGet();}
}

二、饿汉式

  • 懒汉式相对于饿汉式的优势是支持延迟加载。这种实现方式会导致频繁加锁、释放锁,以及并发度低等问题,频繁的调用会产生性能瓶颈。
  • 双重检测实现方式既支持延迟加载、又支持高并发的单例实现方式。只要 instance 被创建之后,再调用 getInstance() 函数都不会进入到加锁逻辑中。所以,这种实现方式解决了懒汉式并发度低的问题。

public class IdGenerator { private AtomicLong id = new AtomicLong(0);private static IdGenerator instance;private IdGenerator() {}public static synchronized IdGenerator getInstance() {if (instance == null) {instance = new IdGenerator();}return instance;}public long getId() { return id.incrementAndGet();}
}// 修改为双重检测,解决性能问题public class IdGenerator { private AtomicLong id = new AtomicLong(0);private static IdGenerator instance;private IdGenerator() {}public static IdGenerator getInstance() {if (instance == null) {synchronized(IdGenerator.class) { // 此处为类级别的锁if (instance == null) {instance = new IdGenerator();}}}return instance;}public long getId() { return id.incrementAndGet();}
}//   instance 成员变量添加 volatile 关键字来禁止指令重排序即

三、静态方法

内部SingletonHolder 在使用到的时候,才会进行创建,jvm保证线程安全


public class IdGenerator { private AtomicLong id = new AtomicLong(0);private IdGenerator() {}private static class SingletonHolder{private static final IdGenerator instance = new IdGenerator();}public static IdGenerator getInstance() {return SingletonHolder.instance;}public long getId() { return id.incrementAndGet();}
}

四、枚举

这种方式最简洁,可以保证不能通过反射实例化,枚举模式的单例还可以防止序列化和反序列化生成新的实例

 
public enum IdGenerator {INSTANCE;private AtomicLong id = new AtomicLong(0);public long getId() { return id.incrementAndGet();}
}

why 有时候不使用单例类会不会更好

一、对单元测试不是很友好
当我们需要改变是实现的时候


public class Order {public void create(...) {//...long id = IdGenerator.getInstance().getId();// 需要将上面一行代码,替换为下面一行代码long id = OrderIdGenerator.getIntance().getId();//...}
}public class User {public void create(...) {// ...long id = IdGenerator.getInstance().getId();// 需要将上面一行代码,替换为下面一行代码long id = UserIdGenerator.getIntance().getId();}
}

二、隐藏类和类之间的依赖关系
三、对扩展性不好

怎么替换单例模式

  1. 使用工厂模式
  2. ioc容器注入

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...