單例模式的理解

目錄

    • 單例模式
      • 1.餓漢式(線程安全)
      • 2.懶漢式(通過synchronized修飾獲取實例的方法保證線程安全)
      • 3.雙重校驗鎖的方式實現單例模式
      • 4.靜態內部類方式實現單例模式【推薦】

單例模式

1.餓漢式(線程安全)

package 并發的例子.單例模式;
// 餓漢式單例模式(天然線程安全,但不支持懶加載)
public class Singleton1 {// 1. 靜態成員變量:在類加載階段(JVM層面)就完成實例化//    - static保證全局唯一一份,類加載時由JVM保證線程安全(僅初始化一次)//    - final修飾防止被意外修改,確保實例不可變private static final Singleton1 INSTANCE = new Singleton1();// 2. 私有構造方法:禁止外部通過new創建實例,保證單例唯一性private Singleton1() {}// 3. 公開靜態方法:提供全局訪問點,直接返回已初始化的實例public static Singleton1 getInstance() {return INSTANCE;}// 測試:驗證多次獲取的是否為同一實例public static void main(String[] args) {Singleton1 instance1 = Singleton1.getInstance();Singleton1 instance2 = Singleton1.getInstance();Singleton1 instance3 = Singleton1.getInstance();// 輸出均為true,證明所有引用指向同一個實例System.out.println(instance1 == instance2);System.out.println(instance2 == instance3);System.out.println(instance1 == instance3);}
}

2.懶漢式(通過synchronized修飾獲取實例的方法保證線程安全)

package 并發的例子.單例模式;
// 懶漢式(通過synchronized修飾獲取實例的方法保證線程安全,但由于整個方法加鎖,效率不高性能略差)
public class Singleton2 {// 定義實例對象引用(僅聲明,未創建實例,實現延遲初始化的基礎)private static Singleton2 instance;// 私有構造方法,防止其他類通過new關鍵字創建實例,確保單例唯一性private Singleton2() {}// 公開的靜態方法,用于獲取單例實例// 使用synchronized修飾方法:保證多線程環境下,同一時間只有一個線程能進入方法,避免創建多個實例public static synchronized Singleton2 getInstance() {// 懶加載(延遲加載):只有當首次調用getInstance()時,才會創建實例對象,節省初始化資源if (instance == null) {instance = new Singleton2();}return instance;}public static void main(String[] args) {// 測試單例模式:多次獲取實例,驗證是否為同一對象Singleton2 s1 = Singleton2.getInstance();Singleton2 s2 = Singleton2.getInstance();Singleton2 s3 = Singleton2.getInstance();// 通過hashCode判斷是否為同一對象(同一對象的hashCode相同)System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println(s3.hashCode());}
}

3.雙重校驗鎖的方式實現單例模式

package 并發的例子.單例模式;// 用雙重校驗鎖的方式實現單例模式
// 簡單說就是:保證整個程序里只有這一個類的對象,而且線程安全、用到時才創建、效率還不錯
public class Singleton3 {// 存單例對象的地方,整個程序就這一個// volatile關鍵字有兩個超能力:// 1. 防止"指令插隊":創建對象的時候步驟必須是【分配內存→初始化對象→給instance賦值】,不能亂序// 2. 保證"看得見":一個線程把對象創建好賦值給instance了,其他線程馬上能看到,不會因為緩存犯傻private static volatile Singleton3 instance;// 把構造方法藏起來,不讓外面用new創建對象// 這樣就只能通過我們寫的getInstance方法來拿對象,保證只有一個private Singleton3() {}// 對外提供的拿單例對象的方法,全局就這一個入口public static Singleton3 getInstance() {// 第一次檢查:先快速看看有沒有對象// 要是已經有了,直接返回,不用走后面的復雜流程,省時間if (instance == null) {// 加鎖排隊:多個線程同時到這的時候,只能一個一個來// 鎖的是整個類(Singleton3.class),保證全局就這一把鎖synchronized (Singleton3.class) {// 第二次檢查:進了鎖之后再看一眼// 防止多個線程都通過第一次檢查后,進來重復創建對象// 要是不檢查,線程1創建完,線程2進來又創建,就不是單例了if (instance == null) {// 真正創建對象的地方// 要是沒加volatile,可能出現"對象還沒初始化好,就把半成品給instance"的情況// 加了volatile就保證步驟是【分配內存→初始化對象→給instance賦值】,穩穩的instance = new Singleton3();}}}// 返回單例對象,不管哪個線程來拿,都是同一個return instance;}
}

4.靜態內部類方式實現單例模式【推薦】

package 并發的例子.單例模式;
// 靜態內部類方式實現單例模式【推薦】
// 特點:線程安全(依托類加載機制) + 懶加載(真正用到實例時才加載) + 簡潔高效
public class Singleton4 {// 1. 私有化構造方法//    作用:禁止外部通過 new Singleton4() 創建對象,確保對象只能通過 getInstance() 獲取private Singleton4() {}// 2. 靜態內部類:SingletonHolder//    特點://    - 靜態內部類不會隨著外部類加載而加載,屬于「懶加載」private static class SingletonHolder {// 3. 靜態內部類中定義單例對象//    - final 保證實例不可變,一旦賦值無法修改//    - 類加載時創建實例,由 JVM 保證線程安全(多線程下不會重復創建)private static final Singleton4 INSTANCE = new Singleton4();}// 4. 對外提供獲取單例的方法public static Singleton4 getInstance() {// 調用此方法時,才會觸發 SingletonHolder 的類加載// 類加載過程中,JVM 會創建 INSTANCE,且保證全局唯一、線程安全return SingletonHolder.INSTANCE;}public static void main(String[] args) {Singleton4 s1 = Singleton4.getInstance();Singleton4 s2 = Singleton4.getInstance();Singleton4 s3 = Singleton4.getInstance();// 通過hashCode判斷是否為同一對象(同一對象的hashCode相同)System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println(s3.hashCode());}
}
1.為什么用靜態內部類?
靜態內部類 SingletonHolder 是 “懶漢”:外部類 Singleton4 加載時,它不會跟著加載,真正調用 getInstance() 時才會加載,實現 “用的時候再創建”(懶加載)。
2.線程安全怎么保證?
JVM 加載類時,會保證 “同一類全局只加載一次”,且加載過程是線程安全的(多線程同時調用 getInstance()SingletonHolder 也只會加載一次)。
因此 INSTANCE 只會創建一次,天然線程安全。
3.對比其他單例的優勢
比 “餓漢式” 懶:餓漢式類加載時就創建實例,靜態內部類做到了 “用的時候才創建”。
比 “懶漢式(同步方法)” 高效:無需手動加鎖,依托 JVM 類加載機制保證線程安全,性能更好。
4.適合場景
需要 懶加載(延遲初始化),且希望 線程安全、代碼簡潔 的場景。
推薦作為日常開發中 “單例模式” 的首選方案,兼顧性能和安全性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95410.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95410.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95410.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NLP---IF-IDF案例分析

一案例 - 紅樓夢1首先準備語料庫http://www.dxsxs.com這個網址去下載2 任務一:拆分提取import os import redef split_hongloumeng():# 1. 配置路徑(關鍵:根據實際文件位置修改) # 腳本所在文件夾(自動獲取&#xff0…

LaTeX(排版系統)Texlive(環境)Vscode(編輯器)環境配置與安裝

LaTeX、Texlive 和 Vscode 三者之間的關系,可以把它們理解成語言、工具鏈和編輯器的配合關系。 1.下載Texlive 華為鏡像網站下載 小編這邊下載的是texlive2025.iso最新版的,下載什么版本看自己需求,只要下載后綴未.iso的即可。為避免錯誤&am…

【深入淺出STM32(1)】 GPIO 深度解析:引腳特性、工作模式、速度選型及上下拉電阻詳解

GPIO 深度解析:引腳特性、工作模式、速度選型及上下拉電阻詳解一、GPIO概述二、GPIO的工作模式1、簡述(1)4種輸入模式(2)4種輸出模式(3)4種最大輸出速度2、引腳速度(1)輸…

第1節 大模型分布式推理基礎與技術體系

前言:為什么分布式推理是大模型時代的核心能力? 當我們談論大模型時,往往首先想到的是訓練階段的千億參數、千卡集群和數月的訓練周期。但對于商業落地而言,推理階段的技術挑戰可能比訓練更復雜。 2025年,某頭部AI公司推出的130B參數模型在單機推理時面臨兩個選擇:要么…

《軟件工程導論》實驗報告一 軟件工程文檔

目 錄 一、實驗目的 二、實驗環境 三、實驗內容與步驟 四、實驗心得 一、實驗目的 1. 理解軟件工程的基本概念,熟悉軟件,軟件生命周期,軟件生存周期過程和軟件生命周期各階段的定義和內容。 2. 了解軟件工程文檔的類別、內容及撰寫軟件工…

基于elk實現分布式日志

1.基本介紹 1.1 什么是分布式日志 在分布式應用中,日志被分散在儲存不同的設備上。如果你管理數十上百臺服務器,你還在使用依次登錄每臺機器的傳統方法查閱日志。這樣是不是感覺很繁瑣和效率低下。所以我們使用集中化的日志管理,分布式日志…

多模態RAG賽題實戰之策略優化--Datawhale AI夏令營

科大訊飛AI大賽(多模態RAG方向) - Datawhale 項目流程圖 1、升級數據解析方案:從 fitz 到 MinerU PyMuPDF(fitz)是基于規則的方式提取pdf里面的數據;MinerU是基于深度學習模型通過把PDF內的頁面看成是圖片…

09--解密棧與隊列:數據結構核心原理

1. 棧 1.1. 棧的簡介 棧 是一種 特殊的線性表,具有數據 先進后出 特點。 注意: stack本身 不支持迭代器操作 主要原因是因為stack不支持數據的隨機訪問,必須保證數據先進后出的特點。stack在CPP庫中實現為一種 容器適配器 所謂容器適配器&a…

打造專屬 React 腳手架:從 0 到 1 開發 CLI 工具

前言: 在前端開發中,重復搭建項目環境是個低效的事兒。要是團隊技術棧固定(比如 React AntD Zustand TS ),每次從零開始配路由、狀態管理、UI 組件,既耗時又容易出錯。這時候,自定義 CLI 腳手架 就派上…

Python day43

浙大疏錦行 Python day43 import torch import numpy as np import pandas as pd import torchvision import torchvision.transforms as transforms import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.utils.data import Da…

python基于Hadoop的超市數據分析系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持: 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具:Navicat/SQLyog等都可以 摘要&…

如何用 COLMAP 制作 Blender 格式的數據集

如何用 COLMAP 制作 Blender 格式的數據集并劃分出 transforms_train.json、transforms_val.json 和 transforms_test.json。 一、什么是 Blender 格式數據集? Blender 格式數據集是 Nerf 和 Nerfstudio 常用的輸入格式,其核心是包含了相機內外參的 JSON 文件,一般命名為:…

[GESP202309 六級] 2023年9月GESP C++六級上機題題解,附帶講解視頻!

本文為GESP 2023年9月 六級的上機題目詳細題解和講解視頻,覺得有幫助或者寫的不錯可以點個贊。 題目一講解視頻 GESP2023年9月六級上機題一題目二講解視頻 題目一:小羊買飲料 B3873 [GESP202309 六級] 小楊買飲料 - 洛谷 題目大意: 現在超市一共有n種飲料&#…

linux 操作ppt

目錄 方法1:用 libreoffice 打開PPT文件 播放腳本: 方法2:用 python-pptx 創建和編輯PPT 方法3:其他方法 在Linux中,可以使用Python通過python-pptx庫來創建和編輯PPT文件,但直接播放PPT文件需要借助其…

元數據管理與數據治理平臺:Apache Atlas 基本搜索 Basic Search

文中內容僅限技術學習與代碼實踐參考,市場存在不確定性,技術分析需謹慎驗證,不構成任何投資建議。 Apache Atlas 框架是一套可擴展的核心基礎治理服務,使企業能夠有效、高效地滿足 Hadoop 中的合規性要求,并支持與整個…

LangChain4J-(1)-Hello World

一、LangChain4J是什么? LangChain4J 是一個專為 Java 生態系統設計的開源框架,用于簡化與大語言模型(LLM,如 OpenAI 的 GPT 系列、Google 的 Gemini、Anthropic 的 Claude 等)的集成和交互。它借鑒了 Python 生態中 L…

HTTPS應用層協議-中間攻擊人

HTTPS應用層協議-中間攻擊人 ? Man-in-the-MiddleAttack,簡稱“MITM 攻擊” 確實,在方案 2/3/4 中,客戶端獲取到公鑰 S 之后,對客戶端形成的對稱秘鑰 X 用服務端給客戶端的公鑰 S 進行加密,中間人即使竊取到了數據&am…

利用 Makefile 高效啟動 VIVADO 軟件:深入解析與實踐

利用 Makefile 高效啟動 VIVADO 軟件:深入解析與實踐 系列文章目錄 1、VMware Workstation Pro安裝指南:詳細步驟與配置選項說明 2、VMware 下 Ubuntu 操作系統下載與安裝指南 3.基于 Ubuntu 的 Linux 系統中 Vivado 2020.1 下載安裝教程 文章目錄利用 …

[前端算法]排序算法

默認情況下,sort() 會將元素轉換為字符串,然后按照 Unicode 編碼的順序進行排序: const fruits [apple, banana, cherry, date]; fruits.sort(); console.log(fruits); // 輸出: ["apple", "banana", "cherry"…

C#標簽批量打印程序開發

C#標簽批量打印程序開發(集成Bartender解決方案)一、系統架構設計 1. 核心模塊劃分 public class LabelPrintingSystem {private IDataLoader _dataLoader; // 數據加載器private ITemplateEngine _templateEngine; // 模板引擎private IPrintControl…