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

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.pswp.cn/web/94695.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win10部署ElasticSearch、Logstash、Kibana

一、本地部署 ElasticSearch 1、下载 Elasticsearch 安装包 点此下载 Elasticsearch 2、解压到指定目录 3、winR 输入 cmd,进入 Elasticsearch 安装目录运行 .bat 文件 4、浏览器输入 https://localhost:9200 ,并进行身份验证 在 Elasticsearch 的 bi…

解决Visual Studio中UWP设计器无法显示的问题:需升级至Windows 11 24H2

一则清晰的错误提示,指明了前进的方向。近日,我在使用Visual Studio进行UWP应用开发时遇到了一个棘手问题——MainPage.xaml的设计视图无法正常显示,取而代之的是一个明确的系统提示。本文将详细分析这一问题及其解决方案。 问题现象 当在Vis…

PINN物理信息神经网络多变量回归预测,Matlab实现

前言 物理信息神经网络(Physics-Informed Neural Networks, PINNs)是一种结合深度学习与物理定律的神经网络方法,旨在解决涉及偏微分方程(PDEs)的问题。以下是对该问题的详细解答:物理信息神经网络的定义与…

SagooIoT 产品国产化

国产化说明,支持的国产化数据库、服务器、操作系统以及国产化中间件。操作系统统一uos操作系统红旗Linux麒麟V10操作系统中天鲲鹏欧拉版本操作系统服务器华为泰山服务器海光服务器华为鲲鹏服务器只要是能兼容Linux操作系统的服务器,你都可以尝试替换。数…

去哪里学AI?2025年AI培训机构推荐!

随着人工智能技术在金融风控、智能医疗、工业制造等领域的加速落地,其已成为全球科技竞争的核心赛道。但人才供给的不足却制约着行业发展,中国信息通信研究院 2024 年发布的《人工智能人才发展报告》显示,我国 AI 领域年度人才缺口已达 720 万…

800G时代!全场景光模块矩阵解锁数据中心超高速未来

引言: 在AI算力爆发与云服务迭代的浪潮下,全球数据中心正加速迈入800G时代。面对激增的带宽需求与严苛的能效挑战,如何选择兼具高性能、低功耗与灵活部署的光模块?全系列800G解决方案已构建完整技术生态,为算力基础设施…

TDengine IDMP 5 个实测场景让监控变简单

概述 在工业#数字化转型 的赛道上,“监控系统搭建” 一直是个让人头疼的难题:传统方案要写 SQL、调脚本、学可视化工具,一套流程走下来少则几天、多则几周,运维新增设备还得重复折腾。但现在,有了 TDengine TSDB TDe…

关于vscode的右键常用操作以及自定义快捷键

最近我一直在使用vscode进行嵌入式开发,我发现比keil好用多了,记录常用右键操作,以及自定义快捷键,记录下来,多希望对大家有所帮助。vscode自定义快捷键F8:跳转到类型定义 只需要将鼠标左键点击变量&…

二、添加3D形状

几何体的生成主要依赖MeshBuilder类添加和管理,包含如下方法: 目录 几何体 1、立方体 AddBox 2、球体 AddShpere 3、圆环 AddTorus 4、锥体或截锥体 AddCone 5、圆柱体 AddCylinder 6、空心管道 AddPipe 7、圆截面管道 AddTube 8、挤压二维截面 AddExtrudeGeometry…

Excel 表格 - 乘法与除法处理(保留两位小数四舍五入实现、保留两位小数截断实现、添加百分号)

乘法函数 1、保留两位小数四舍五入实现 (1)基本介绍 ROUND(【单元格 1】 * 【单元格 2】, 2)【单元格 1】 * 【单元格 2】:基本的乘法运算ROUND(..., 2):外层函数,将结果四舍五入到指定的小数位数,2 表示保…

【AI基础:神经网络】20、机器学习实战:自组织特征映射(SOM)完全指南

一、引言:为什么SOM是“看不见的手”调控的神经网络? 在机器学习的无监督领域,有一类神经网络格外特殊——它不需要人工标注的“标准答案”,仅通过数据自身的特征和网络内部的简单规则,就能自发形成有序的结构,将高维、混乱的数据“梳理”成低维、可解释的拓扑映射。这一…

深入解析十大经典排序算法原理与实现

排序算法示例说明文档 概述 本文档详细说明了排序算法示例的实现原理、性能特点和使用方法。 功能概要:提供各种排序算法的完整实现,包括基础排序算法和高级排序算法,帮助理解算法原理和性能特点 排序算法分类 1. 基础排序算法 (Basic S…

微服务-26.网关登录校验-OpenFeign传递用户信息

一.OpenFeign传递用户信息前端发起的请求都会经过网关再到微服务,由于我们之前编写的过滤器和拦截器功能,微服务可以轻松获取登录用户信息。但有些业务是比较复杂的,请求到达微服务后还需要调用其它多个微服务。比如下单业务,流程…

Java:IO流——增强篇

目录 前言 一、缓冲流——让数据传输飞起来 🚀 1、缓冲思想 2、缓冲字节流 3、缓冲字符流 二、标准流——程序三大通道🚦 1、标准输入流(System.in) 2、标准输出流(System.out) 3、标准错误流(S…

指针 (六):sizeof和strlen细节强化之“做题篇”

目录 1. sizeof和strlen的对比 1.1 sizeof 1.2 strlen 1.3 sizeof 和 strlen的对比 2. 数组和指针笔试题解析 2.1 ⼀维数组 2.2 字符数组 代码1: 代码2: 代码3: 代码4: 代码5: 代码6: 2.3 二维数组 3. 指针…

java中的数据类型

1 概述 Java 是一门面向对象的编程语言,其核心原则之一是一切皆对象。然而,基本数据类型(如 int、double、char 等)并非对象,不具备对象的特性,例如不能调用方法、不能参与继承体系等。而包装类&#xff08…

【系统分析师】高分论文:论信息系统开发方法及应用

【摘要】 本文以某国有企业的 B2B 商品棉交易平台的电子商务门户网站系统(以下简称“门户网站”)建设为例,讨论信息系统开发方法及应用。本文作者认为项目实施中选择合适的开发方法,既能满足用户需求,又能提高整个项目…

开源 C++ QT Widget 开发(七)线程--多线程及通讯

文章的目的为了记录使用C 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。 相关链接: 开源 C QT Widget 开发(一)工程文件结构-CSDN博客 开源 C…

CPU-IO-网络-内核参数的调优

CPU-IO-网络-内核参数的调优CPU-IO-网络-内核参数的调优一、CPU 资源调优1.1 调整进程优先级(nice 值)1.2 设置 CPU 亲和力(taskset)1.3 cpu命令描述1.4 使用 vmstat 分析系统瓶颈二、磁盘 I/O 调优2.1 ulimit 资源限制2.2 测试磁…

JavaScript 实战进阶:工程化、性能与未来展望

一、JavaScript 工程化实践 随着前端项目规模的扩大,“工程化”成为提升开发效率、保证代码质量的核心手段。它涵盖模块化设计、构建工具链、代码规范与测试等多个维度。 (一)模块化开发 模块化是将复杂代码拆分为可复用、可维护的独立单元的…