從雙重檢查鎖定的設計意圖、鎖的作用、第一次檢查提升性能的原理三個角度,詳細拆解單例模式的邏輯

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
英文地址,請注明出處:http://en.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 工程化實踐 隨著前端項目規模的擴大,“工程化”成為提升開發效率、保證代碼質量的核心手段。它涵蓋模塊化設計、構建工具鏈、代碼規范與測試等多個維度。 (一)模塊化開發 模塊化是將復雜代碼拆分為可復用、可維護的獨立單元的…