【JAVA ee初階】多線程(3)

一、出現線程安全的原因

1.【根本原因】線程的調度執行時隨機的(搶占式執行)->罪魁禍首

2.多個線程同時修改同一個變量

如果是一個線程修改一個變量 或者 多個線程讀取同一個變量 或者 多個線程修改不同變量 這些都沒事。

3.修改操作不是原子的!

像count++ 這樣的修改,就是不是原子的修改。

但是像 = 這樣的修改,就是屬于原子的。(在Java針對內置類型進行 = ,或者針對引用 = 都是原子的)(*但是,在C++中就不一定了,還是不是原子的,就得具體問題具體分析了)

后序判定某個代碼是否是線程安全的,需要結合這幾點一起來判定。

*如果將全局變量count放入到main方法當中,就會出現報錯。

把變量改成局部變量,編譯直接過不了了:lambda表達式要想正確捕獲變量,要求是final或者事實final(雖然沒有加final關鍵字,但是代碼中確實也沒人修改)

寫成成員變量在lambda中確實能夠使用,此時不是走“變量捕獲”語法,而是“內部類訪問外部類成員”,本身就ok。

lambda本質上就是匿名 內部類(函數式接口)

內部類訪問外部類成員,本來就可以實現。

*擴展String?

String是不可變對象,new好一個String對象本身就是不能修改的。設計成不可變對象,其中有一個理由,就是不可變對象天然就是線程安全的。

不可變對象,方便放到常量池中進行緩存。不可變對象,hasCode是固定值,也方便和哈希表進行結合,作為hash的Key

StringBuffer本身確實修改了,但是又通過其他路徑(例如枷鎖)解決線程安全問題。

StringBuilder是徹底的線程不安全。

*什么是原子的?一個事物是原子的,說明他就是不可拆分的最小單位。SQL中,事務就是把多個SQL打包成一個整體,執行的時候,要么全都執行完,要么一個都不執行。就不會出現執行一半的情況,這就成為原子性。

此處談到的原子也是類似的含義,CPU執行指令的角度,如果是一條指令,對于CPU來說,要么就是執行完,要么就是不執行,不會出現“一個指令執行一般”這樣的情況。CPU執行一條指令,這個行為就是原子的。

像count++這樣的指令,對應到多條CPU指令,CPU執行過程中就可能執行一半,就調度走執行別人的指令了(這就不是原子的)

=這樣的操作,也是對應到一條CPU指令(類似于MOVE)

那么如何將這些操作變為線程安全的呢?

核心思路:把修改操作變成原子的。

通過鎖來實現。

關鍵字:synchronized通過這個關鍵字來實現使用鎖。

對于鎖這樣的概念,涉及到兩個核心操作:

1.加鎖

2.解鎖

Java就通過這一個關鍵字來表示這兩種操作,進來就是加鎖,出去就是解鎖。sychronized()的()里面填寫的是“鎖對象”,真正用來枷鎖的鎖是誰?——>在Java中,任何一個對象都可以用來作為鎖對象(引用類型,不能是內置類型)

加鎖,就是把若干個操作“打包成一個原子”。不是說把這count++的三個指令變成一個指令了。也不是說,這三個指令就必須要一口氣在cpu上執行完,不會觸發調度。加鎖會影響到其他的加鎖線程,而且是加同一個鎖的線程。

當兩個線程,嘗試競爭同一把鎖,才會產生“阻塞”,如果是競爭不同的鎖,就沒有影響。

sychronized(鎖對象),看鎖對象是不是同一個對象。

鎖競爭(Lock Contention)是指多個線程試圖同時訪問同一個臨界區(即需要互斥訪問的代碼區域),因此它們之間產生了競爭。在任意時刻,只能有一個線程持有鎖并進入臨界區,其他試圖進入臨界區的線程必須等待。

如果是兩個線程,一個加鎖了另一個么有加鎖,這樣就不會產生阻塞。兩個線程都加鎖了,而且是同一個對象,才會產生鎖競爭。

此處的加鎖和解鎖,也可以視為兩個cpu指令。這兩個操作使得這兩個線程各自循環執行5w次。

整個程序按照如圖所示的流程進行:

本來load add save 在兩個線程中是穿插執行的,但是在引入鎖之后,就變成了“串行執行”,不再穿插,最后輸出結果也自然是1w次。

*要是兩個鎖對象不一樣:不一樣就不會產生阻塞,程序的執行也就不會出現上述的“禁止插隊”這樣的行為。

這里又一系列很復雜的邏輯這里也有一系列很復雜的邏輯

日常工作中,一般都是讓加鎖范圍盡量的小

這樣的話,可以并發執行的邏輯就更多,此時外部的邏輯通常是更復雜的。

此時這張圖中,只有count++是串行的。

引入多線程,就是為了并發執行,就是為了充分利用cpu多核心資源。

多進程編程 和 多線程編程 就是在利用多核心的編程手法。

t1如果加上鎖,t1就會不停地執行循環,直到把5w次都執行完,才會去釋放鎖。

t2只能阻塞等待,一直等到t1釋放鎖(t1的5w次循環都執行完了),t2才能繼續執行

此時,這兩個線程的循環時完全串行的,(也就是和一個線程執行是類似的了),這種寫法,兩個代碼是完全串行化。

此時,并沒有把多核心利用起來。

這種寫法,在當前代碼下,執行速度反而更快,主要是因為當前的任務很簡單。

*這種情況下,t1和t2誰先拿到鎖?

結論沒有唯一性,假設t1先拿到鎖,當t1循環完畢一次,下一次加鎖可能是t1繼續加上,也可能是t2加上(這里體現了隨機調度)。類似于“數據庫隔離級別”,隔離級別越高,并發程度越低,執行速度越慢。

synchronized使用方法

1.synchronized(鎖對象){}

基礎使用,常見使用。不是禁止調度,而是禁止其他線程插隊。

2.修飾一個普通方法,就可以省略鎖對象:

*此時,相當于針對this加鎖,不是沒有鎖對象,而是把鎖對象給省略掉了

等價于

上面這兩種寫法,實際上沒有任何區別。鎖對象,是啥對象不重要,重要的是,兩個線程是否是針對同一個對象加鎖。

3.synchronized修飾靜態方法

此時認為synchronized是針對類對象進行加鎖的

static修飾的方法,也叫做“類方法”,不是針對“實例”的方法,而是針對類的。在這個方法里,沒有this。

Counter.class——>反射 程序運行時,能夠拿到類/對象的一些相關屬性。(這個類有哪些成員,都叫啥名字,都是啥類型,都是private/public,有啥方法,都叫啥名,參數列表是啥,是private/public,這個類繼承的父類是誰,上實現了哪些interface.......)

通過類對象拿到上述信息。(*不考慮運行,看下代碼就行,強調“運行時”的意思就是,不讓你看代碼,也能夠獲取到這里的信息)

.java編譯生成.class?

.class被jvm加載到內存中,就得到了對應的“類對象”。

synchronized的特性

1.互斥性(前文已經提及)

2.可重入

如果一個線程,針對一把鎖,連續加鎖兩次會發生死鎖(deadlock)。(如圖所示)

分析:初始情況下,假定locker是未加鎖的狀態,此時的synchronized就會加鎖成功,繼續向下執行。

第二次加鎖的時候,這個鎖已經是“被加鎖”的狀態了,如果這個鎖已經被加鎖了,嘗試加鎖操作,就會觸發鎖沖突/鎖競爭,此時該線程就會阻塞等待,一直等到鎖被釋放。

走到第二個加鎖的位置,觸發阻塞,如何解除阻塞?得先釋放第一個鎖,如何釋放第一個鎖,得先把第二個鎖加上,往下繼續走。

BLOCKED狀態不是“死鎖”,而是因為鎖產生的阻塞,這里所說的死鎖指的是這個鎖再也解不開了。

有的時候,死鎖的現象不是特別明顯,稍有不慎就會發生死鎖現象。

但是,java中引入了可重入機制,有效地避免了上述的死鎖情況。(注意,死鎖有很多種體現形式,可重入只是能解決一個線程一把鎖,加鎖兩次的情況,解決不了其他情況)同一個線程,針對同一把鎖,連續加鎖多次,不會觸發死鎖,此時這個鎖就可以稱為“可重入鎖”。

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

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

相關文章

Halcon 3D 表面匹配基于形狀

文章目錄 prepare_object_model_3d 準備 3D 物體模型read_shape_model_3d — 讀取3D匹配模型create_shape_model_3d 準備要匹配的3D模型find_shape_model_3d ——發現匹配模型project_shape_model_3d 將三維形狀模型的邊緣投影到圖像坐標中。示例ignore_part_polarity&#xff…

【Linux】Java 開發者的 Linux 常用命令指南

Java 開發者的 Linux 常用命令指南 目錄標題 Java 開發者的 Linux 常用命令指南1. Linux 目錄結構2. 系統信息命令3. 服務管理系統服務防火墻管理 4. 文本編輯 (vi/vim)常用模式 5. 文件和目錄操作查看與導航創建與刪除查看文件內容查找文件 6. 用戶管理7. 壓縮和解壓8. 權限管…

每日c/c++題 備戰藍橋杯(P1252洛谷 馬拉松接力賽)

洛谷P1060 馬拉松接力賽題解:貪心算法在資源分配中的巧妙應用 題目描述 P1060 馬拉松接力賽是一道結合貪心策略與動態規劃思想的資源分配問題。題目要求將25公里的馬拉松接力賽合理分配給5名選手,使得總耗時最短。每位選手可跑1-10公里的整數距離&…

Nginx 中間件

Nginx(發音為 "engine-x")是一款開源的高性能 HTTP 服務器和反向代理服務器,最初由 Igor Sysoev 開發。 它以其高性能、穩定性、豐富的功能集和低資源消耗而聞名,廣泛應用于全球的 Web 服務架構中。 作為中間件&#…

Neo4j在win下安裝教程(docker環境)

1. 安裝命令 1.1 基于正式neo4j安裝–不用 docker run --name neo4j-container -p 7474:7474 -p 7687:7687 -d neo4j1.2 基于community安裝 需要部署兩個Neo4j,一個正式庫prod,一個測試庫dev。 neo4j默認監聽7474(HTTP-也就是瀏覽器端口&…

kylin v10 + argo + ascend 310p多機多卡 pytorch distributed 訓練

最近接了個模型訓練編排多機多卡的改造需求,要求使用argo dag task啟動多個節點,同時多個節點能實現 torch.distributed.launch 這樣多機多卡的訓練模式 簡述技術 torch.distributed.launch命令介紹 我們在訓練分布式時候,會使用到 torch.d…

[Mac] 使用homebrew安裝miniconda

使用虛擬環境可以對不同項目的依賴進行隔離。可以使用venv或者conda來創建和使用虛擬環境。 venv是Python內置的虛擬環境管理模塊,適合純Python項目以及快速輕量級的開發和部署。conda具備更強大的版本管理能力,但是占用較大的磁盤空間。 考慮到我基本不…

CMU-15445(1)——環境搭建

前言 最近在找完暑期實習之后,終于有了一些干項目外的空余時間學習新的知識,在這么多輪面試中,數據庫的考察非常多,但孱弱的數據庫基礎導致我有很多次面試被問住,因此我希望在學習CMU-15445(Fall 2024&…

CSS元素動畫篇:基于當前位置的變換動畫(四)

基于當前位置的變換動畫(四) 前言透明效果類元素動畫閃爍動畫效果效果預覽代碼實現 淡入動畫效果效果預覽代碼實現 淡出動畫效果效果預覽代碼實現 結語 前言 CSS元素動畫一般分為兩種:一種是元素基于當前位置的變換動畫,通過不明…

STM32驅動AD5318配置8通道DA詳細講解

目錄 1. AD5318 芯片特性 2、AD5318寄存器概述 3、SPI數據幀格式 3.1 控制位(Bit15) 3.2 地址位(Bit14-Bit12,3 位) 3.3 數據 / 控制碼(Bit11-Bit0) 4、控制功能寄存器(控制位 = 1 時激活) 4.1 參考與增益配置(MM = 00) 4.2. LDAC模式(MM = 01) 4.3 掉…

如何搭建spark yarn 模式的集群集群

以下是搭建Spark YARN模式集群的一般步驟: 準備工作 - 確保集群中各節點安裝了Java環境,并配置好 JAVA_HOME 環境變量。 - 各節點間能通過SSH免密登錄。 - 安裝并配置好Hadoop集群,YARN作為Hadoop的資源管理器,Spark YARN模式需要…

SpringMVC處理請求映射路徑和接收參數

目錄 springmvc處理請求映射路徑 案例:訪問 OrderController類的pirntUser方法報錯:java.lang.IllegalStateException:映射不明確 核心錯誤信息 springmvc接收參數 一 ,常見的字符串和數字類型的參數接收方式 1.1 請求路徑的…

在 Windows 系統上升級 Node.js

一、查詢電腦端已經安裝的 Node.js 版本 1、通過【winR】 鍵,輸入 cmd,點擊【確定】按鈕打開 cmd 窗口 2、命令行界面輸入 node -v 查看目前 Node.js 版本 3、命令行界面輸入 npm -v 查看目前 npm 版本 二、進入官網地址下載安裝包 1、官網地址&#x…

深入詳解人工智能數學基礎——概率論中的馬爾可夫鏈蒙特卡洛(MCMC)采樣

?? 博主簡介:CSDN博客專家、CSDN平臺優質創作者,高級開發工程師,數學專業,10年以上C/C++, C#, Java等多種編程語言開發經驗,擁有高級工程師證書;擅長C/C++、C#等開發語言,熟悉Java常用開發技術,能熟練應用常用數據庫SQL server,Oracle,mysql,postgresql等進行開發應用…

C++ 嵌套類 (詳解 一站式講解)

目錄 嵌套類 嵌套類的定義 嵌套類結構的訪問權限 pimpl模式(了解) 嵌套類 嵌套類的定義 首先介紹兩個概念: 類作用域(Class Scope) 類作用域是指在類定義內部的范圍。在這個作用域內定義的成員(包括…

tcp 和http 網絡知識

1. 請簡述TCP和HTTP的定義與基本概念 TCP:即傳輸控制協議(Transmission Control Protocol),是一種面向連接的、可靠的、基于字節流的傳輸層通信協議。它為互聯網中的數據通信提供穩定的傳輸機制,在不可靠的IP層之上&a…

MySQL安裝的多個組件中無用組件卸載

在決定卸載MySQL的哪些組件前,需根據你的實際使用場景判斷。以下是各組件的主要功能及卸載建議: 1. 核心組件卸載建議 組件名稱作用是否可卸載MySQL Server數據庫服務核心,存儲數據、處理SQL請求的核心程序。不可卸載 (卸載會導致…

CosyVoice 技術全景解析:下一代語音生成模型的革命性突破

目錄 一、CosyVoice 模型概述 1. 背景與定位 二、技術架構與創新 1. 核心架構設計 2. 關鍵技術亮點 三、行業地位與競品對比 1. 市場定位分析 2. 競爭優勢 四、部署方案與硬件成本 1. 硬件需求 2. 優化技巧 五、優勢與挑戰 1. 核心優勢 2. 主要挑戰 六、開源生態…

rabbitmq-集群部署

場景:單個pod,部署在主節點,基礎版沒有插件,進階版多了一個插件 基礎版本: --- apiVersion: v1 kind: PersistentVolume metadata:name: rabbitmq-pv spec:capacity:storage: 5GiaccessModes:- ReadWriteOncestorage…

[密碼學實戰]商用密碼產品密鑰體系架構:從服務器密碼機到動態口令系統

[密碼學實戰]商用密碼產品密鑰體系架構:從服務器密碼機到動態口令系統 關鍵詞:商用密碼、密鑰體系、服務器密碼機、金融數據密碼機、動態口令、智能密碼鑰匙 摘要:本文深度解讀商用密碼產品的核心密鑰體系架構,涵蓋服務器密碼機、金融數據密碼機、VPN產品、動態口令系統及…