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

从双重检查锁定的设计意图、锁的作用、第一次检查提升性能的原理三个角度,详细拆解单例模式的逻辑

public class SFTPUtil {// 16 usages(注释为截图中的使用统计,实际代码无需保留)private static ChannelSftp sftp;// 6 usages(注释为截图中的使用统计,实际代码无需保留)private volatile static SFTPUtil instance = null;// 1 usage(注释为截图中的使用统计,实际代码无需保留),私有构造方法,防止外部直接实例化private SFTPUtil() {}public static SFTPUtil getInstance(String host, int port, String username, String password) {// 日志打印 instance 是否为 null,{} 是占位符,实际会替换为 true/falselog.info("---------> instance == null :{}", instance == null);if (instance == null) {// 类级别的同步锁,保证多线程下仅初始化一次synchronized (SFTPUtil.class) {if (instance == null) {// 创建 SFTPUtil 实例instance = new SFTPUtil();// 获取 SFTP 连接,并赋值给静态变量 sftpsftp = instance.connect(host, port, username, password);}}}return instance;}// 截图中未展示 connect 方法的具体实现,需补充(根据上下文推测是建立 ChannelSftp 连接的逻辑)private ChannelSftp connect(String host, int port, String username, String password) {// 这里需补充实际连接 SFTP 服务器的代码,示例如下(基于 JSch 库):ChannelSftp channelSftp = null;try {JSch jsch = new JSch();Session session = jsch.getSession(username, host, port);session.setPassword(password);// 跳过严格主机密钥检查(测试环境可用,生产环境需配置 known_hosts)session.setConfig("StrictHostKeyChecking", "no"); session.connect();Channel channel = session.openChannel("sftp");channel.connect();channelSftp = (ChannelSftp) channel;} catch (JSchException e) {// 实际需完善异常处理,比如日志记录或抛出自定义异常log.error("SFTP 连接失败", e);}return channelSftp;}// 若有其他工具方法(如下载、上传等),需补充...public downLoadZipMethod(){// 执行下载 ".ok" 文件
SFTPUtil sf = SFTPUtil.getInstance(props.getSftpHost(), Integer.parseInt(props.getSftpPort()), props.getSftpUsername(), props.getSftpPassword()
);
}
}

这块代码是什么时候会调用会每次调用downloadZipFile都会调用这个SFTPUtil.getInstance(),走到第二个图的逻辑,第二个图中每一次都会返回一个新的SFTPUtil实例吗?第二个图中所加的锁是什么作用?

以下从 实例创建逻辑锁的作用是否每次返回新实例 三个维度详细分析:

1. 实例创建逻辑:是否每次返回新实例?

不会每次返回新实例,因为代码用了 单例模式(双重检查锁定),核心逻辑:

private volatile static SFTPUtil instance = null;public static SFTPUtil getInstance(...) {if (instance == null) { // 第一次检查(无锁,提升性能)synchronized (SFTPUtil.class) { // 加类锁,保证线程安全if (instance == null) { // 第二次检查(避免多线程重复创建)instance = new SFTPUtil(); // 仅第一次调用时创建实例sftp = instance.connect(...); }}}return instance; // 后续调用直接返回已创建的实例
}
  • 结论:无论调用 getInstance 多少次,全局仅会创建 1 个 SFTPUtil 实例(单例特性)。

2. 锁的作用:synchronized (SFTPUtil.class)

synchronized (SFTPUtil.class)类级别的锁,作用是:

  • 保证线程安全:在多线程环境下,避免多个线程同时进入 if (instance == null) 逻辑,导致重复创建 SFTPUtil 实例。
  • 实现单例的核心:通过双重检查(if (instance == null) 两次判断) + 类锁,确保 instance = new SFTPUtil() 仅执行一次。

3. downloadZipFile 调用 getInstance 的时机

每次调用 downloadZipFile 方法时,都会执行:

SFTPUtil sf = SFTPUtil.getInstance(...);

但由于 getInstance 是单例逻辑,只有第一次调用 会触发 new SFTPUtil()sftp = instance.connect(...);后续调用直接返回已存在的 instance

潜在问题与优化建议

(1)单例与多环境冲突

如果 getInstance 的入参(hostport 等)在不同调用中变化,但实例已创建,会导致后续调用使用第一次的参数(比如第一次用 host=192.168.1.1 创建实例,后续传入 host=10.0.0.1 也不会重新创建实例)。

风险:若业务需要连接不同 SFTP 服务器,单例模式会导致参数失效。

解决方案

  • 放弃单例,改为每次创建新实例(去掉 instance 静态变量,直接 new SFTPUtil() );
  • 或根据入参(hostport 等)维护多个单例(用 Map 缓存不同参数对应的实例)。
(2)sftp 静态变量的线程安全

private static ChannelSftp sftp; 是静态变量,若多线程同时使用 sftp 执行操作(如 cdget ),会引发线程安全问题(不同线程操作同一个 ChannelSftp 可能导致命令混乱)。

解决方案

  • sftp 改为实例变量(非静态),每个 SFTPUtil 实例持有独立的 sftp 通道;
  • 或对 sftp 的操作加锁(synchronized 或使用线程安全的工具类)。
(3)连接未释放的风险

SFTPUtil 是单例且长期运行,sftp 通道可能因超时、网络波动断开,且没有重连逻辑,会导致后续操作失败。

解决方案

  • 添加连接校验与重连逻辑(在 download 前检查 sftp.isConnected() ,断开则重新 connect );
  • 实现 close 方法,在业务结束时主动释放连接。

总结

  • 是否每次返回新实例:否,全局仅 1 个实例(单例模式)。
  • 锁的作用:保证多线程下仅创建 1 个实例,线程安全。
  • 潜在问题:单例与多参数冲突、sftp 静态变量线程不安全、连接未释放。

若业务需要连接不同 SFTP 服务器,或多线程操作 sftp ,建议调整单例逻辑或增加线程安全处理。

http://www.xdnf.cn/news/1370971.html

相关文章:

  • Markdown学习笔记(4)
  • 矩阵微积分的链式法则(chain rule)
  • 在 Android Studio 中修改 APK 启动图标(2025826)
  • 从线到机:AI 与多模态交互如何重塑 B 端与 App 界面设计
  • 【RAGFlow代码详解-23】聊天系统架构
  • 【LeetCode 热题 100】75. 颜色分类——双指针
  • PWM控制实现呼吸灯
  • 家庭财务规划与投资系统的设计与实现(代码+数据库+LW)
  • Linux SSH 基于密钥交换的自动登录:原理与配置指南
  • (Arxiv-2024)VideoMaker:零样本定制化视频生成,依托于视频扩散模型的内在力量
  • 进程管理详解
  • 如何将视频从安卓设备传输到Mac?
  • 2025改版:npm 新淘宝镜像域名地址
  • 【数据结构】树和二叉树——二叉树
  • 使用字节旗下的TREA IDE快速开发Web应用程序
  • Python中函数的闭包和装饰器
  • 读懂支持向量机(SVM)
  • C++ STL 顶层设计与安全:迭代器、失效与线程安全
  • 【Python实战练习】用 Python与Pygame 打造完整的贪吃蛇小游戏
  • 懂支持向量机(SVM):从原理到实战拆解
  • 机器学习模型可解释库的介绍:Shapash (一)
  • 深度学习(五):正则化:约束模型的复杂度
  • Python 全局变量使用
  • 声明式微服务通信新范式:OpenFeign如何简化RestTemplate调用
  • 乳腺癌数据集支持向量机实践学习总结
  • `stat` 系统调用详解
  • AI应用--接口测试篇
  • 实训日志day28
  • Elasticsearch中的设置refresh_interval
  • 文献阅读笔记【雷达辐射源识别】:Recognition of Unknown Radar Emitters with Machine Learning