并發編程(5)

拋異常時會釋放鎖。

當線程在?synchronized?塊內部拋出異常時,會自動釋放對象鎖。

public class ExceptionUnlockDemo {private static final Object lock = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {synchronized (lock) {System.out.println("線程1獲取到鎖");try {// 模擬操作Thread.sleep(1000);// 拋出異常throw new RuntimeException("模擬異常");} catch (InterruptedException | RuntimeException e) {System.out.println("線程1捕獲異常: " + e.getMessage());}// 異常發生后,鎖已經被釋放System.out.println("線程1執行完畢");}});Thread t2 = new Thread(() -> {// 短暫等待,確保t1先執行try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("線程2嘗試獲取鎖");synchronized (lock) {System.out.println("線程2獲取到鎖");}});t1.start();t2.start();}
}

結果:

線程1獲取到鎖
線程1捕獲異常: 模擬異常
線程2嘗試獲取鎖
線程2獲取到鎖
線程1執行完畢

從輸出能夠看出,線程 1 在拋出異常之后,線程 2 就能夠獲取到鎖,這表明線程 1 的鎖已經因為異常而被釋放了。

加鎖的區域就是同步代碼塊

在 Java 中,被鎖保護的代碼區域被稱為同步代碼塊(Synchronized Block)。當多個線程訪問同一把鎖的同步代碼塊時,會強制串行執行,從而保證線程安全。同步的意思就是說比如說一個線程在執行時訪問了一個別鎖的共享資源,在時間片結束后還占著資源,另一個線程也不能訪問

public class SynchronizedExample {private final Object lock = new Object();  // 鎖對象// 方法級同步(隱式鎖為 this)public synchronized void method1() {// 同步方法的代碼}// 代碼塊級同步(顯式指定鎖對象)public void method2() {synchronized (lock) {// 同步代碼塊,同一時刻只能被一個線程執行}}
}

monitor進monitor出

對于我們人來說,一個程序的執行開始和執行結束是可以理解的,但機器不行。我們計算機內部的指令經過編譯之后是一長串的代碼,程序以數組的形式存到頁里,我們加的鎖的區域在數組里不允許同時被訪問。那么我們需要一些表記指出哪些區域的代碼是被鎖的不能同時訪問。

首先我們要進行范圍標記枷鎖加鎖我們知道這塊資源是加鎖標記還得。注意我們加鎖是這樣的。

第一,我們對要操作的資源加上所標記。

第二,我們要操作的資源這塊是有這些指令對資源進行操作,這一堆指令要對資源進行操作,其中指令到這些區域。這些區域對它的操作不能是同時進行的,所以我們加鎖的話有兩個區域,一個是對資源本身加標記,另外一個對操作的資源的指令。也得指定所在的范圍同步范圍。

?monitor進monitor出就是標記這些指令里那一塊是不能同時被線程所操作。

JAVA對象頭

snchronized用的鎖是存在Java對象頭里的。如果對象是數組類型,則虛擬機用3個字寬(Word)存儲對象頭,如果對象是非數組類型,則用2字寬存儲對象頭。在32位虛擬機中,1字寬等于4字節,即32bit.

我們在堆區域創建對象,每一個對象都有鎖表記和對象表記,所屬類型:類的地址指向方法區。

如果有數組的話有數組長度。

如果一個64位的操作系統可以安裝32位或64位的程序。32位的操作系統只可以安裝32位程序。如果cpu的一個時鐘周期能夠運算32位,那他只能安裝32位的操作系統。那如果一個程序是64位的程序,它里邊一個字寬就是64位。是32位的程序,那么它就只能說一個字寬是32位。從這個推理下,我們在64位的操作系統下安裝了32位的程序,那么它一個字就是32位。也就是說字寬最終是受程序的位數影響

?
鎖的升級與對比

在 Java 中,鎖的升級是 JVM 為了優化鎖性能而引入的機制。隨著多線程競爭的加劇,鎖會從無鎖狀態逐步升級為偏向鎖、輕量級鎖,最終升級為重量級鎖。這種升級過程是不可逆的,旨在平衡不同競爭程度下的性能開銷。

1.?鎖升級的流程

鎖的狀態會根據競爭情況逐步升級:

無鎖 → 偏向鎖 → 輕量級鎖 → 重量級鎖

1.1?無鎖狀態(Normal)
  • 特點:對象頭的 Mark Word 存儲哈希碼、分代年齡等信息。
  • 場景:沒有線程訪問同步塊時。
1.2?偏向鎖(Biased Locking)
  • 適用場景:只有一個線程頻繁訪問同步塊。
  • 原理
    • 首次獲取鎖時,JVM 會在 Mark Word 中記錄線程 ID(通過 CAS 操作)。
    • 該線程后續進入同步塊時,無需任何同步操作,直接判斷 Mark Word 中的線程 ID 是否匹配。
  • 優點無競爭時幾乎無額外開銷,性能最優。
  • 缺點:當其他線程嘗試競爭鎖時,需要撤銷偏向鎖,消耗 CPU。

?

?

1.3?輕量級鎖(Lightweight Locking)
  • 適用場景:多個線程交替訪問同步塊(無競爭)。
  • 原理
    • 線程在棧幀中創建鎖記錄(Lock Record),并通過 CAS 將 Mark Word 復制到鎖記錄中。
    • 同時,Mark Word 會指向鎖記錄的地址。
    • 如果 CAS 成功,線程獲得輕量級鎖;如果失敗,表示有競爭,鎖會升級為重量級鎖。
  • 優點:競爭不激烈時避免線程阻塞,減少用戶態和內核態的切換。不進阻塞隊列,快速循環看看自己請求的資源有沒有解鎖。
  • 缺點:頻繁 CAS 操作可能消耗 CPU。
1.4?重量級鎖(Heavyweight Locking)
  • 適用場景:多個線程同時競爭鎖。
  • 原理
    • 依賴操作系統的互斥量(Mutex),線程會被阻塞并進入等待隊列。
    • 鎖釋放時,需要喚醒等待的線程,涉及用戶態和內核態的切換。
  • 缺點:線程阻塞和喚醒的開銷大,性能最差。重量解鎖的加鎖和解鎖都挺麻煩,不僅僅是修改對象頭標記這么簡單,還有很多枷鎖過程,枷鎖競爭過程。
?四種鎖的對比
特性無鎖偏向鎖輕量級鎖重量級鎖
適用場景無同步需求單線程訪問多線程交替訪問多線程同時競爭
實現方式Mark Word 存儲哈希碼等信息Mark Word 存儲線程 IDMark Word 指向線程棧中的鎖記錄Mark Word 指向 Monitor 對象
線程狀態無需阻塞無需阻塞自旋等待阻塞等待
性能開銷最低低(首次 CAS)中等(CAS 操作)最高(內核態切換)
優缺點無同步開銷無競爭時最優避免線程切換線程頻繁阻塞 / 喚醒
釋放機制無需釋放線程退出同步塊時不釋放,其他線程競爭時撤銷解鎖時通過 CAS 恢復 Mark Word解鎖時喚醒等待線程

現在是幾個線程對資源進行競爭只有一個才能競爭成功!只有一個競爭成功加上了鎖。其他就會競爭失敗。競爭失敗的話會競爭失敗會進阻塞隊列。為什么進入阻塞隊列:成功的線程即使時間片到期了,下次還是選中他可以立馬執行。效率最高每個加鎖資源對應一個阻塞隊列
?

?然后第一個成功占資源的線程已經執行結束后,會給所有在阻塞隊列的線程發通知,讓他們回到就緒隊列。

比較并且交換

比較并交換(Compare-and-Swap, CAS)?是一種實現無鎖(Lock-Free)算法的原子操作,用于在多線程環境中實現同步。它允許線程在不使用鎖的情況下安全地修改共享數據,從而避免了鎖帶來的上下文切換和線程阻塞開銷。這種方式也是實現了寫后讀。

  • 如果內存地址 V 中的值等于預期舊值 A,則將該位置的值更新為新值 B,并返回?true
  • 如果內存地址 V 中的值不等于預期舊值 A,則不執行更新,返回?false

但也有缺點,他是分兩步的先比較再交換。比如說線程1先比較,發現沒問題可以交換,但此時時間片到期。線程2進入也比較發現也沒問題,也要交換就有問題了。?他不是原子操作,所以無法實現。只能調用操作系統底層。

流水線技術。他減少了電路的切換。提升的整體速度。但是指令順序會發生變化,會導致后邊有個指令重排序導致的并發問題。

java中哪些類是線程安全的?concurrent 開頭的是線程安全的集合。Atomic. 開頭的也是線程安全的

private AtomicInteger atomicI = new AtomicInteger(0);private int i = 0;public static void main(String[] args) {final Counter cas = new Counter();List<Thread> ts = new ArrayList<Thread>(600);long start = System.currentTimeMillis();for (int j = 0; j < 100; j++) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {cas.count();cas.safeCount();}}});ts.add(t);}for (Thread t : ts) {t.start();}// 等待所有線程執行完成for (Thread t : ts) {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(cas.i);System.out.println(cas.atomicI.get());System.out.println(System.currentTimeMillis() - start);}/**        * 使用CAS實現線程安全計數器        */private void safeCount() {for (;;) {int i = atomicI.get();boolean suc = atomicI.compareAndSet(i, ++i);if (suc) {break;}}}/*** 非線程安全計數器*/private void count() {i++;}}

一個使用AtomicInteger實現的線程安全計數器atomicI,另一個是普通的非線程安全整數i。在多線程環境下運行這兩個計數器,會看到不同的結果。

主要分析

  1. 線程安全問題

    • count()方法使用普通的i++操作,在多線程環境下會出現競態條件(Race Condition),導致最終結果小于預期值。
    • safeCount()方法使用AtomicInteger和 CAS 操作,保證了原子性,最終結果是正確的。
  2. CAS 操作的實現

    for (;;) {int i = atomicI.get();boolean suc = atomicI.compareAndSet(i, ++i);if (suc) {break;}
    }
    
    ?

    這段代碼通過循環 CAS 操作來保證原子性:

    • 獲取當前值
    • 嘗試更新為新值
    • 如果失敗則重試,直到成功
  3. 性能考慮

    • 原子操作雖然避免了鎖的開銷,但在高競爭環境下可能會因為頻繁重試而降低效率
    • 非原子操作雖然沒有這些開銷,但結果是錯誤的,所以不能只考慮性能

輸出結果

對于 100 個線程,每個線程執行 10000 次遞增操作:

  • atomicI.get()的輸出結果應為:100 * 10000 = 1,000,000
  • i的輸出結果通常會小于 1,000,000,因為非線程安全操作會導致部分遞增丟失
  • 執行時間取決于系統環境,但通常原子操作會比非原子操作慢一些
  • ?我們看由于它沒有加鎖。他100萬字肯定有相互覆蓋,最終的結果肯定不到100萬,就極大概率不到100萬,有沒有看到100萬的一個極小的可能?比較大的可能是到不了100萬。因為會有相互覆蓋的問題。能理解的加九。對他100萬次調用

?ABA問題

在多線程編程中,ABA 問題(ABA Problem)是使用?CAS(Compare-and-Swap)?操作時可能遇到的一種特殊問題。它發生在一個值從 A 變為 B,然后再變回 A 的過程中,而 CAS 操作無法感知這個中間變化,誤認為值沒有被修改過。

1.?ABA 問題的本質

CAS 操作的核心邏輯是:“如果當前值是預期值 A,則將其更新為 B”。但如果在檢查期間,值經歷了?A → B → A?的變化,CAS 會認為值 “沒有變化” 并成功更新,而實際上值已經被其他線程修改過,可能導致潛在的錯誤。

2.?ABA 問題示例

假設有一個共享變量?int value = 10,兩個線程 T1 和 T2 同時操作它:

  1. T1 讀取 value:T1 準備將?value?從 10 增加到 11,它先讀取?value?的當前值為 10。
  2. T2 修改 value:T2 先將?value?改為 20,然后又改回 10(即?10 → 20 → 10)。
  3. T1 執行 CAS:T1 執行?CAS(預期值=10, 新值=11),發現當前值確實是 10,認為沒有變化,成功將?value?改為 11。

問題:T1 認為?value?沒有被修改過,但實際上它經歷了?10 → 20 → 10?的變化,可能導致 T1 的操作基于錯誤的假設(例如,T1 可能期望?value?自從讀取后沒有被其他線程動過)。

3.?ABA 問題的危害

  • 數據一致性風險:在某些業務邏輯中,中間狀態的變化可能影響最終結果。例如:
    • 鏈表操作:刪除節點 A,插入新節點 B(內容與 A 相同),此時 CAS 可能誤判節點未變。
    • 賬戶余額:余額從 100 變為 200 再變回 100,CAS 可能允許重復扣款。
  • 邏輯錯誤:某些操作依賴值的連續性變化,而 ABA 可能破壞這種假設。

4.解決方法

解決 ABA 就加版本號就可以了

線程可見性

一個線程對共享變量做出了修改,其他線程能及時讀取到最新的修改,這叫線程可見性
?

線程間如何通信和進程間如何通信

進程是由線程組成的。進程所有的功能線程全都有。進程所擁有的功能線程全都有。然后。線程擁有的功能進程不一定有進程的通信方式線程全都有

里邊通信其實是指交換信息的意思,就把消息傳遞過去,線程的通信方式有兩種共享內存和消息傳遞
?

?

?

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

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

相關文章

貴州某建筑物擋墻自動化監測

1. 項目簡介 某建筑物位于貴州省某縣城區內&#xff0c;靠近縣城主干道&#xff0c;周邊配套學校、醫院、商貿城。建筑物臨近鳳凰湖、芙蓉江等水系&#xff0c;主打“湖景生態宜居”。改建筑物總占地面積&#xff1a;約5.3萬平方米&#xff1b;總建筑面積&#xff1a;約15萬平…

6個月Python學習計劃:從入門到AI實戰(前端開發者進階指南)

作者&#xff1a;一名前端開發者的進階日志 計劃時長&#xff1a;6個月 每日學習時間&#xff1a;2小時 覆蓋方向&#xff1a;Python基礎、爬蟲開發、數據分析、后端開發、人工智能、深度學習 &#x1f4cc; 目錄 學習目標總覽每日時間分配建議第1月&#xff1a;Python基礎與編…

【FAQ】HarmonyOS SDK 閉源開放能力 —Vision Kit (3)

1.問題描述&#xff1a; 通過CardRecognition識別身份證拍照拿到的照片地址&#xff0c;使用該方法獲取不到圖片文件&#xff0c;請問如何解決&#xff1f; 解決方案&#xff1a; //卡證識別實現頁&#xff0c;文件名為CardDemoPage&#xff0c;需被引入至入口頁 import { …

AI全域智能監控系統重構商業清潔管理范式——從被動響應到主動預防的監控效能革命

一、四維立體監控網絡技術架構 1. 人員行為監控 - 融合人臉識別、骨骼追蹤與RFID工牌技術&#xff0c;身份識別準確率99.97% - 支持15米超距夜間紅外監控&#xff08;精度0.01lux&#xff09; 2. 作業過程監控 - UWB厘米級定位技術&#xff08;誤差&#xff1c;0.3米&…

安全強化的Linux

SElinux簡介 SELinux是security-Enhanced Linux的縮寫,意思是安全強化的linux SELinux主要由美國國家安全局(NSA)開發,當初開發的目的是為了避免資源的誤用。傳統的訪問控制在我們開啟權限后,系統進程可以直接訪問 當我們對權限設置不嚴謹時,這種訪問方式就是系統的安全漏洞 在…

機器學習第十六講:K-means → 自動把超市顧客分成不同消費群體

機器學習第十六講&#xff1a;K-means → 自動把超市顧客分成不同消費群體 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;超詳細手把手指南 K-me…

spring中yml配置上下文與tomcat等外部容器不一致問題

結論&#xff1a;外部優先級大于內部 在 application.yml 中配置了&#xff1a; server:port: 8080servlet:context-path: /demo這表示你的 Spring Boot 應用的上下文路徑&#xff08;context-path&#xff09;是 /demo&#xff0c;即訪問你的服務時&#xff0c;URL 必須以 /d…

論文研讀——《AnomalyGPT:使用大型視覺語言模型檢測工業異常》

這篇論文提出了 AnomalyGPT&#xff0c;一個基于大型視覺語言模型的工業異常檢測框架&#xff0c;首次將通用多模態對話能力引入工業視覺場景&#xff0c;通過引入圖像解碼器增強像素級感知&#xff0c;設計 Prompt 學習器實現任務自適應控制&#xff0c;并利用合成異常樣本解決…

供應鏈安全檢測系列技術規范介紹之一|軟件成分分析

軟件成分分析的概念及意義 軟件成分分析Software Compostition Analysis&#xff08;SCA&#xff09;是一種用于管理開源組件應用安全的方法。軟件成分分析系統可以快速跟蹤和分析應用軟件的開源組件&#xff0c;發現相關組件、支持庫以及它們之間直接和間接依賴關系&#xff0…

conda更換清華源

1、概覽 anaconda更換速度更快、更穩定的下載源&#xff0c;在linux環境測試通過。 2、conda源查看 在修改之前可以查看下現有conda源是什么&#xff0c;查看conda配置信息&#xff0c;如下&#xff1a; cat ~/.condarc 可以看到你的conda源&#xff0c;以我的conda源舉例&am…

Docker配置容器開機自啟或服務重啟后自啟

要將一個 Docker 容器設置為開機自啟&#xff0c;你可以使用 docker update 命令或配置 Docker 服務來實現。以下是兩種常見的方法&#xff1a; 方法 1&#xff1a;使用 docker update 設置容器自動重啟 使用 docker update 設置容器為開機自啟 你可以使用以下命令&#xff0c…

Flink 的水印機制

Apache Flink 的 水印機制&#xff08;Watermark Mechanism&#xff09; 主要用于解決 事件時間流中的亂序問題&#xff08;Out-of-Order Events&#xff09;&#xff0c;確保窗口&#xff08;Window&#xff09;能夠在合適的時間觸發計算&#xff0c;從而提供準確、一致的處理…

【每天一個知識點】embedding與representation

“Embedding&#xff08;嵌入&#xff09;”與“Representation&#xff08;表示&#xff09;”在機器學習、自然語言處理&#xff08;NLP&#xff09;、圖神經網絡等領域常被使用&#xff0c;它們密切相關&#xff0c;但語義上有一定區別。 一、定義 1. Representation&#…

SpringBoot(二)--- SpringBoot基礎(http協議、分層解耦)

目錄 前言 一、SpringBoot入門 1.入門程序 2.解析 二、HTTP協議 1.HTTP概述 2.HTTP請求協議 2.1 GET方式的請求協議 2.2 POST方式的請求協議 2.3 兩者的區別 2.4 獲取請求數據 3.HTTP響應協議 三、分層解耦 1.三層架構 2.IOC&DI 2.1 入門 2.2 IOC詳解 2.…

Please install it with pip install onnxruntime

無論怎么安裝都是 Please install it with pip install onnxruntime 我python 版本是3.11 &#xff0c;我換成3.10 解決了

【數據結構入門訓練DAY-35】棋盤問題

本次訓練聚焦于使用深度優先搜索&#xff08;DFS&#xff09;算法解決棋盤上的棋子擺放問題。題目要求在一個可能不規則的nn棋盤上擺放k個棋子&#xff0c;且任意兩個棋子不能位于同一行或同一列。輸入包括棋盤大小n和棋子數k&#xff0c;以及棋盤的形狀&#xff08;用#表示可放…

【日常筆記】wps如何將值轉換成東西南北等風向漢字

在WPS表格中&#xff0c;若要將數值&#xff08;如角度值&#xff09;轉換成“東、南、西、北”等風向漢字&#xff0c;可通過以下步驟結合自定義函數或條件判斷實現&#xff1a; 一、wps如何將值轉換 方法一&#xff1a;使用LOOKUP函數&#xff08;簡化公式&#xff09;&…

Web性能優化的未來:邊緣計算、AI與新型渲染架構

一、邊緣計算與性能優化深度整合 1.1 邊緣節點計算卸載策略 ? 智能任務分割:將非關鍵路徑計算卸載到邊緣節點 // 客戶端代碼 const edgeTask = new EdgeTask(image-processing); edgeTask.postMessage(imageData, {transfer

spring中的EnvironmentPostProcessor接口詳解

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到網站 EnvironmentPostProcessor 是 Spring Boot 提供的一個關鍵擴展接口&#xff0c;允許開發者在 Spring 應用環境初始化后、應用上下文創建前&…

Vue3知識點梳理

注&#xff1a;純手打&#xff0c;如有錯誤歡迎評論區交流&#xff01; 轉載請注明出處&#xff1a;https://blog.csdn.net/testleaf/article/details/148056625 編寫此文是為了更好地學習前端知識&#xff0c;如果損害了有關人的利益&#xff0c;請聯系刪除&#xff01; 本文章…