【Java】多線程-單例模式/volatile-指令重排序

單例模式即代碼中只有一個實例的模式

適用場景:有些場景下,有的類只能有一個對象,不能有多個

要注意:在單例模式下,要保證不能產生多個實例

1、餓漢模式

class Singleton{private static Singleton instance = new Singleton();public static Singleton getSingleton() {return instance;}private Singleton(){}
}public class demo {public static void main(String[] args) {Singleton singleton1 = Singleton.getSingleton();Singleton singleton2 = Singleton.getSingleton();System.out.println(singleton1==singleton2);System.out.println(singleton1.equals(singleton2));}
}

將構造方法設為private,使得不能自己初始化類,?只能用默認給定的類

由于是單例,所以singleton1與singleton2地址內容都是一樣的,兩者是同一個實例

2、 懶漢模式

(1)懶漢模式-不安全

class SingletonLazy{private static SingletonLazy instance = null;public static SingletonLazy getSingletonLazy() {if(instance == null){instance = new SingletonLazy();}return instance;}private SingletonLazy(){}
}public class demo {public static void main(String[] args) {SingletonLazy singletonLazy1 = SingletonLazy.getSingletonLazy();SingletonLazy singletonLazy2 = SingletonLazy.getSingletonLazy();System.out.println(singletonLazy1 == singletonLazy2);System.out.println(singletonLazy1.equals(singletonLazy2));}
}

餓漢模式中,無論原來有沒有創建instance,都會初始化一個新的instance

懶漢模式為了節約開銷,會在getSingletonLazy()方法中判斷instance是否是null。如果不是null,說明instance已經初始化,只須直接返回即可;如果是第一次獲取,那么instance沒有初始化,是null,這時初始化后再返回

(2)懶漢模式-線程安全

上面的代碼存在的問題是:由于判斷if(instance == null)這一步和初始化instance = new SingletonLazy()這一步是分開的,有可能會出現線程安全問題

???????

如上圖,T1和T2都各創建了一個instance實例,從而出現了兩個實例,破壞了單例模式的規則

為了解決上述線程安全問題,我們在getSingletonLazy()方法中對這段代碼進行加鎖(靜態方法代碼塊加鎖對象用類名.class)

public static SingletonLazy getInstance() {synchronized (SingletonLazy.class){if(instance == null){instance = new SingletonLazy();}}return instance;}

(3)空間浪費

改成加鎖代碼后,產生了一個新問題,那就是:每次獲得instance時都要進行加鎖,但是加鎖本身是一項耗費空間資源的操作,這樣便會大大降低代碼性能

如果我們能夠得知實例已經創建,那么就不用再進行加鎖了,所以在加鎖之前我們對instance進行一次判斷

public static SingletonLazy getInstance() {if(instance == null){synchronized (SingletonLazy.class){if(instance == null){instance = new SingletonLazy();}}}return instance;
}

注意,第一次判斷和第二次判斷作用并不一樣:第一次是為了判斷是否需要加鎖;第二次是為了判斷是否需要新創建實例

(4)指令重排序問題

經過兩次優化,上述代碼仍存在問題,那就是——指令重排序問題

?· 什么是指令重排序問題呢

當我們在new一個對象的時候,new這個過程分為三步

1.申請內存空間
2.在內存空間上構造對象 (構造方法)

3.把內存的地址,賦值給 instance 引用

這個過程可以按照123來執行,也可以按照132的順序來執行?

在我們上述優化過的代碼中,如果T1線程在new的過程中按照132的順序來執行,那么在執行到第二步時,恰好T2第一次對instance進行判斷,由于instance已經創建了實例,那么T2會直接返回這個沒有構造對象的instance

如果代碼中對返回的instance進行訪問屬性/方法等操作,程序就會報錯

?· volatile

為了解決這個問題,我們使用了volatile關鍵字來對instance變量進行修飾

這樣,在進行new操作時,就不會產生指令重排序問題

class SingletonLazy{private static volatile SingletonLazy instance = null;public static SingletonLazy getInstance() {if (instance == null){synchronized (SingletonLazy.class){if (instance == null){instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}

volatile解決內存可見性問題

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

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

相關文章

Mybatis plus 簡介

簡介 MyBatis-Plus (opens new window)(簡稱 MP)是一個 MyBatis (opens new window)的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。 官網:https://baomidou.com/pages/24112f/ 特性 無侵入&…

英語常見的21組重點必背短語

短語: at at once 立刻,馬上 at least 至少 at most 最多 at last 最后 at home 在家 at noon 在中午 at night 在夜晚 at times 有時,偶爾 at school 在上學 at table 在吃飯 at present 目前,現在 at work 在工作 at all 全然&#xff0c…

《QT從基礎到進階·三十八》QWidget實現炫酷log日志打印界面

QWidget實現了log日志的打印功能,不僅可以在界面顯示,還可以生成打印日志。先來看下效果,源碼放在文章末尾: LogPlugin插件類管理log所有功能,它可以獲取Log界面并能打印正常信息,警告信息和錯誤信息&…

runnergo全棧測試平臺

一、全棧測試平臺runnergo使用 官網 官方使用文檔 二、單接口測試 三、性能測試 1.性能測試 2.性能測試報告 四、自動化測試(暫時不支持UI自動化,或許會上)

Jmeter 壓測實戰保姆級入門教程

1、Jmeter本地安裝 1.1、下載安裝 軟件下載地址: https://mirrors.tuna.tsinghua.edu.cn/apache/jmeter/binaries/ 選擇一個壓縮包下載即可 然后解壓縮后進入bin目錄直接執行命令jmeter即可啟動 1.2 修改語言 默認是英文的,修改中文,點擊…

使用Java Servlet生成動態二維碼

文章目錄 引入ZXing庫創建QRCodeServlet部署到Servlet容器拓展功能1. 動態生成二維碼內容2. 調整二維碼尺寸3. 錯誤修正級別4. 日志輸出 結語 🎉歡迎來到Java學習路線專欄~探索Java中的靜態變量與實例變量 ☆* o(≧▽≦)o *☆嗨~我是IT陳寒🍹?博客主頁&…

【追求卓越04】數據結構--棧與隊列

引導 今天我們開始學習棧與隊列的內容,我覺得棧并不難,所以篇幅也就不會那么多了。在虛擬空間中,棧是用戶空間中的一種數據結構,它主要用于保存局部變量。那么問題來了,為什么用棧來保存局部變量,不用別的數…

Spring Boot 3 集成 Knife4j

基礎環境 SpringBoot : 3.0.6 Java: jdk-17.0.5 Maven: 3.6.1依賴 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xs…

Go 語言函數、參數和返回值詳解

函數是一組語句&#xff0c;可以在程序中重復使用。函數不會在頁面加載時自動執行。函數將通過調用函數來執行。 創建函數 要創建&#xff08;通常稱為聲明&#xff09;一個函數&#xff0c;請執行以下操作&#xff1a; 使用 func 關鍵字。指定函數的名稱&#xff0c;后跟括…

Java編程技巧:if-else優化實踐總結歸納

文/朱季謙 說實話&#xff0c;其實我很討厭在代碼里大量使用if-else&#xff0c;一是因為該類代碼執行方式屬于面向過程的&#xff0c;二嘛&#xff0c;則是會顯得代碼過于冗余。這篇筆記&#xff0c;主要記錄一些自己在工作實踐當中針對if-else的優化心得&#xff0c;將會不定…

10年開發工程師總結,8大主流程序員兼職平臺,月入30k不是夢!

今年互聯網行業陸續裁員減薪&#xff0c;許多人怨聲載道的同時也開始另謀出路。而對于程序員更是應該提早做好準備&#xff0c;活躍在兼職接單的最前沿。 我們程序員是一門技術工種&#xff0c;與互聯網其他行業相比薪水會相對高一點&#xff0c;不過錢也不是那么好賺的&#…

C++中類和動態內存分配

new關鍵字 在C中&#xff0c;內存分為棧和堆。棧中的對象生命周期較短&#xff0c;往往在作用域結束后就會銷毀&#xff0c;而堆中的對象生命周期較長&#xff0c;只有當使用delete或者程序結束時才會銷毀。而new則是將我們創建的對象分配到堆中&#xff0c;使對象可以跨作用域…

2023年【廣東省安全員B證第四批(項目負責人)】報名考試及廣東省安全員B證第四批(項目負責人)復審考試

題庫來源&#xff1a;安全生產模擬考試一點通公眾號小程序 廣東省安全員B證第四批&#xff08;項目負責人&#xff09;報名考試是安全生產模擬考試一點通總題庫中生成的一套廣東省安全員B證第四批&#xff08;項目負責人&#xff09;復審考試&#xff0c;安全生產模擬考試一點…

json_to_mask

修改后的json_to_dataset文件&#xff0c;直接復制替換你自己原始的json_to_dataset&#xff0c;建議保存一下原版import argparse import base64 import json import os import os.path as ospimport imgviz import PIL.Imagefrom labelme.logger import logger from labelme …

java:springboot單元測試spring-boot-starter-test

背景 Java的單元測試可以使用多個框架&#xff0c;其中比較流行的包括&#xff1a; JUnit&#xff1a;JUnit是Java單元測試最常用的框架&#xff0c;它提供了一套豐富的API&#xff0c;可以方便地編寫測試用例和測試套件。JUnit 5是JUnit的最新版本&#xff0c;引入了許多新功…

ElMessageBox中的子組件回調關閉函數

父組件中&#xff1a; const closeMessageBox () > {ElMessageBox.close();getList(); };const open () > {ElMessageBox({title: 添加商品,message: h(AddTaxExemption, { onClose: closeMessageBox }),customClass: custom-message-box, showConfirmButton: false,d…

各大電商平臺雙十一“狂飆”,如何選擇商城系統?

今年是“雙十一”的第十五年。作為各大平臺和品牌的全年最重要的營銷節點&#xff0c;品牌們可謂是來勢洶洶&#xff0c;各種促銷活動和優惠力度讓人眼花繚亂。 淘天數據顯示&#xff0c;天貓促銷活動開售當晚&#xff0c;155個品牌開賣成交額突破1億元&#xff1b;首小時內7.1…

str轉wstr的三種方法和從網站獲取json數據到數據隨機提取,返回拼接字符串和動態數組

庫的設置 hv庫 外部包含目錄&#xff1a;…\include\libhv_new\hv; 庫目錄&#xff1a;…\include\libhv_new\lib\x86\Release; 附加依賴項&#xff1a;hv.lib; //Get請求 獲取json數據&#xff0c;然后提取符合 條件的&#xff0c;time值大于自定義變量的值&#xff0c;然后取…

【UE】用樣條線實現測距功能(上)

目錄 效果 步驟 一、創建樣條網格體組件3D模型 二、實現點擊連線功能 三、實現顯示兩點間距離功能 效果 步驟 一、創建樣條網格體組件3D模型 創建一個圓柱模型&#xff0c;這里底面半徑設置為10mm&#xff0c;高度設置為1000mm 注意該模型的坐標軸在如下位置&#xff1…

基于pytest的服務端http請求的自動化測試框架?

1、引言 我有一個朋友是做 Python 自動化測試的。前幾天他告訴我去參加一個大廠面試被刷了。 我問他是有沒有總結被刷下來的原因。他說面試官問了一些 pytest 單元測試框架相關的知識&#xff0c;包括什么插件系統和用力篩選。但是他所在的公司用的技術是基于 unittest 的&am…