volatile、synchronized和Lock

名詞解釋:

指令重排是計算機為了優化執行效率,在不改變單線程程序結果的前提下,對代碼的執行順序進行重新排列的操作。它可能發生在編譯階段(編譯器優化)或CPU運行階段(處理器優化)。


舉個栗子🌰:做飯的步驟

假設你要做一道菜,步驟是:

  1. 洗鍋 → 2. 熱油 → 3. 放菜 → 4. 翻炒

指令重排后可能變成

  1. 洗鍋 → 3. 放菜(未熱油) → 2. 熱油 → 4. 翻炒
    單線程下沒問題(最終菜還是熟的),但多線程下可能翻車(其他線程看到“放菜”時油還沒熱)!

為什么需要指令重排?

  • 提高執行效率:CPU和編譯器會通過重排指令,充分利用硬件資源(如并行執行不沖突的操作)。
  • 減少等待時間:避免因某些操作(如內存讀取延遲)導致的空閑等待。

多線程環境中的問題

指令重排在單線程無感知,但在多線程并發時可能導致意外結果

經典案例:雙重檢查鎖(DCL)單例模式

public class Singleton {private static Singleton instance;public static Singleton getInstance() {if (instance == null) {                    // 第一次檢查synchronized (Singleton.class) {if (instance == null) {            // 第二次檢查instance = new Singleton();    // 問題在此!}}}return instance;}
}

問題分析
instance = new Singleton() 實際分為三步:

  1. 分配內存空間
  2. 初始化對象
  3. 將引用指向內存地址

指令重排可能導致步驟2和3顛倒
→ 其他線程可能在對象未初始化完成時,拿到非空的instance,導致使用錯誤!


如何禁止指令重排?

  1. 使用 volatile 關鍵字
    → 修飾變量(如 private volatile static Singleton instance;),通過插入內存屏障禁止重排序。
    → 解決上述DCL單例問題。

  2. 使用 synchronizedLock
    → 同步代碼塊保證原子性和可見性,隱含禁止重排序。


總結

  • 指令重排:優化手段,單線程安全,多線程需警惕。
  • 解決方案volatile 或同步機制確保多線程下的順序一致性。

在 Java 中,volatilesynchronizedLock 是解決并發問題的三種重要工具。它們有不同的使用場景和特點,下面分別介紹它們的用途、常用方法以及適用場景。


1. volatile

用途

  • 保證可見性:確保一個線程對共享變量的修改對其他線程立即可見。
  • 防止指令重排序:通過插入內存屏障(Memory Barrier)禁止某些編譯器或處理器的指令重排序優化。

特點

  • 只適用于單個變量。
  • 不保證復合操作(如x++)的原子性。
  • 開銷較小,性能優于synchronized

常用場景

  • 用于狀態標志位(如開關標志)。
  • 當只需要保證可見性和有序性時使用。

例子

class VolatileExample {private volatile boolean flag = true;public void stop() {flag = false; // 修改flag,其他線程會立即看到}public void run() {while (flag) {// 執行任務}System.out.println("Thread stopped");}
}

2. synchronized

用途

  • 保證互斥性:同一時刻只有一個線程可以執行被同步保護的代碼塊。
  • 保證可見性:當一個線程釋放鎖時,會將修改后的變量值刷新到主存中,其他線程獲取鎖時會從主存中讀取最新值。
  • 防止指令重排序:通過插入內存屏障確保有序性。

特點

  • 可以作用于代碼塊或方法。
  • 提供了內置鎖機制,簡單易用。
  • 性能較低(相對volatile),但在復雜場景下更可靠。

常用方法/用法

  1. 同步方法

    • 使用synchronized修飾方法,鎖定當前對象(即this)。
    public synchronized void increment() {count++;
    }
    
  2. 同步代碼塊

    • 使用synchronized修飾代碼塊,指定鎖對象。
    public void increment() {synchronized (lock) {count++;}
    }
    
  3. 靜態同步方法

    • 鎖定的是類對象(Class實例)。
    public static synchronized void incrementStatic() {staticCount++;
    }
    

例子

class SynchronizedExample {private int count = 0;public synchronized void increment() {count++; // 線程安全}public synchronized int getCount() {return count;}
}

3. Lock(ReentrantLock)

用途

  • 提供比synchronized更靈活的鎖機制
    • 支持公平鎖和非公平鎖。
    • 支持嘗試獲取鎖(tryLock())。
    • 支持可中斷鎖(lockInterruptibly())。
    • 支持超時獲取鎖(tryLock(long timeout, TimeUnit unit))。
  • 保證互斥性、可見性和有序性

特點

  • 需要手動加鎖和解鎖(容易忘記解鎖,導致死鎖)。
  • 提供更多功能,但使用復雜度更高。
  • 性能通常優于synchronized(尤其是在高競爭情況下)。

常用方法

  1. 核心接口:java.util.concurrent.locks.Lock

    • void lock():獲取鎖,如果鎖不可用則阻塞。
    • void unlock():釋放鎖。
    • boolean tryLock():嘗試獲取鎖,成功返回true,失敗返回false
    • boolean tryLock(long timeout, TimeUnit unit):嘗試在指定時間內獲取鎖。
    • void lockInterruptibly():獲取鎖,但可以響應中斷。
  2. 實現類:ReentrantLock

    • 可重入鎖,支持公平鎖和非公平鎖。

例子

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class LockExample {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock(); // 加鎖try {count++; // 線程安全} finally {lock.unlock(); // 釋放鎖}}public int getCount() {lock.lock();try {return count;} finally {lock.unlock();}}
}

對比總結

特性volatilesynchronizedLock(ReentrantLock)
互斥性不支持支持支持
可見性支持支持支持
有序性支持(禁止重排序)支持支持
原子性不支持復合操作支持支持
靈活性
性能高(高競爭下優于synchronized
適用場景單個變量的狀態標志方法或代碼塊的同步需要高級功能(如嘗試鎖、公平鎖等)

選擇建議

  1. 優先使用volatile
    • 如果只需要保證可見性和有序性,并且不涉及復合操作。
  2. 使用synchronized
    • 如果需要簡單的互斥性、可見性和有序性,且不需要額外的功能。
  3. 使用Lock
    • 如果需要更靈活的鎖機制(如嘗試鎖、超時鎖、公平鎖等)。

通過合理選擇工具,可以在保證線程安全的同時,提升程序的性能和可維護性。

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

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

相關文章

嵌入式八股C語言---面向對象篇

面向對象與面向過程 面向過程 就是把整個業務邏輯分成多個步驟,每步或每一個功能都可以使用一個函數來實現面向對象 對象是類的實例化,此時一個類就內部有屬性和相應的方法 封裝 在C語言里實現封裝就是實現一個結構體,里面包括的成員變量和函數指針,然后在構造函數中,為結構體…

Distilling the Knowledge in a Neural Network知識蒸餾

一.知識蒸餾的定義 1. 量化VS蒸餾 量化:減小精度 例如參數float32—>float16蒸餾:Student model模仿Teacher model,在保持較高性能的同時,減少模型大小和計算復雜度的技術。 二.知識蒸餾步驟 1.教師模型訓練: 訓練一個大型且復雜的神…

靜態程序分析

參考:https://github.com/RangerNJU/Static-Program-Analysis-Book/blob/master/SUMMARY.md 課件:https://pascal-group.bitbucket.io/teaching.html 視頻:南京大學《軟件分析》課程01(Introduction)_嗶哩嗶哩_bilib…

Flutter_學習記錄_device_info_plus 插件獲取設備信息

引入三方庫device_info_plus導入頭文件 import package:device_info_plus/device_info_plus.dart;獲取設備信息的主要代碼 DeviceInfoPlugin deviceInfoPlugin DeviceInfoPlugin(); BaseDeviceInfo deviceInfo await deviceInfoPlugin.deviceInfo;完整案例 import package…

日有所得-google 瀏覽器離線安裝

一、目標: 基于UOS系統進行瀏覽器插件開發,目標展現形式為側欄 二、背景: UOS操作系統需支持1032及以上版本 瀏覽器插件基于google瀏覽器,自帶360等瀏覽器能兼容基于google瀏覽器開發的插件 JS庫借用Vue庫以提高效率 三、問…

高效自動化測試:打造Python+Requests+Pytest+Allure+YAML的接口測試框架

一、背景 在快節奏的開發周期中,如何確保接口質量?自動化測試是關鍵。通過構建標準化、可復用的測試框架,能顯著提升測試效率與準確性,為項目質量保駕護航[1][7]。 二、目標 ? 核心目標: ● 實現快速、高效的接口測試…

談談List,Set,Map的區別

List、Set 和 Map 是 Java 集合框架(Java Collections Framework)中的三種主要接口,它們各自有不同的特點和用途。以下是它們的區別和使用場景的詳細解釋: 1. List(列表) 1.1 特點 有序集合:Li…

智能運維管理系統的主要優勢

智能運維管理系統通過整合大數據、人工智能、機器學習等技術,顯著提升了IT運維的效率和質量。以下是智能運維管理系統的主要優勢: 一、提升運維效率 1.自動化運維 自動執行重復性任務(如日志分析、故障排查、系統備份)&#xf…

分享一個用來解決運維問題的 AI 提示詞

模板如下&#xff08;每次我都是自己寫的&#xff0c;但是感覺可以更加調優一些&#xff09; 我遇到了如下問題<問題的清晰描述>你是一位資深運維工程師&#xff0c;任務是指導我一步步排查并解決上面的問題排查過程中&#xff0c;你給我操作指示&#xff0c;我將操作的…

【python運行Janus-Pro-1B文生圖功能】

前言 體驗了一把本地部署Janus-Pro-1B實現文生圖功能。 1、開源項目下載 官方開源項目代碼直接從Github上下載。 2、模型下載 模型官方下載需要魔法 Janus-Pro-1B模型文件&#xff1a;Janus-Pro-1B模型文件 百度網盤&#xff1a; https://pan.baidu.com/s/16t4H4z-QZe2UDAg4…

跨越時空的對話:圖靈與GPT-4聊AI的前世今生

&#xff08;背景&#xff1a;虛擬咖啡廳&#xff0c;圖靈身著1950年代西裝&#xff0c;端著一杯熱茶&#xff0c;GPT-4以全息投影形態坐在對面&#xff09; 圖靈&#xff08;喝了口茶&#xff09;&#xff1a;“聽說你能寫詩&#xff1f;我當年在布萊切利園破解Enigma時&…

L2-4 吉利矩陣

輸入樣例&#xff1a; 7 3輸出樣例&#xff1a; 666 這道題是暴力純搜&#xff0c;但是很難想&#xff0c;我這個是看的別人的代碼 #include "bits/stdc.h" using namespace std; int x[20][20]; int l, n; int cnt 0; int sumx[5], sumy[5]; void dfs(int x, in…

Quickwit+Jaeger+Prometheus+Grafana搭建Java日志管理平臺

介紹 生產服務應用可觀測性在當下比較流行的方案&#xff0c;其中出現了大量高性能、開箱即用、易上手的的開源產品&#xff0c;大大豐富了在可觀測性領域產品的多樣性&#xff0c;本文講述基于OTLP協議推送Java項目遙測數據&#xff08;日志、指標、鏈路&#xff09;到后端存儲…

SpringMVC (一)基礎

目錄 SpringMVC 一 簡單使用 1 新建模塊選擇指定參數 2 創建實現類 3 將項目啟動 4 運行結果&#xff1a;在瀏覽器當中響應執行 二 RequestMapping 三 請求限定 SpringMVC SpringMVC是Spring的web模塊&#xff0c;用來開發Web應用&#xff0c;SpringMVC應用最終作為B/…

【機器人-基礎知識】歐拉角、旋轉矩陣和四元數

1. 歐拉角 1.1. 歐拉角的定義 歐拉角是一組三個角度,用于描述一個剛體在三維空間中的定向關系。具體來說,它們表示從一個固定參考坐標系到剛體坐標系的一系列旋轉。常見的定義方式是將總體旋轉分解為三個連續的簡單旋轉,每次旋轉都繞著當前坐標系的某一固定軸進行。 例如,…

xxl-job部署在docker-destop,實現定時發送預警信息給指定郵箱

XXL-JOB XXL-JOB是一個分布式任務調度平臺&#xff08;XXL是作者徐雪里姓名拼音的首字母&#xff09;&#xff0c;其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。 源碼倉庫地址&#xff1a;https://github.com/xuxueli/xxl-job 源碼結構&#xff1a; 系統架構 在xxl-j…

大數據學習(63)- Zookeeper詳解

&&大數據學習&& &#x1f525;系列專欄&#xff1a; &#x1f451;哲學語錄: 用力所能及&#xff0c;改變世界。 &#x1f496;如果覺得博主的文章還不錯的話&#xff0c;請點贊&#x1f44d;收藏??留言&#x1f4dd;支持一下博主哦&#x1f91e; &#x1f…

【數據結構】3順序表

0 章節 &#xff12;&#xff0e;&#xff11;到&#xff12;&#xff0e;&#xff13;小節。 理解與表達線性表的邏輯結構&#xff1b; 線性表的結構、結構與操作&#xff1b; 順序表的表示與實現&#xff1b;順序表應用&#xff1b; 重點 線性表概念、順序表定義運算與實現&a…

CUDA編程之OpenCV與CUDA結合使用

OpenCV與CUDA的結合使用可顯著提升圖像處理性能。 一、版本匹配與環境配置 CUDA與OpenCV版本兼容性? OpenCV各版本對CUDA的支持存在差異&#xff0c;例如OpenCV 4.5.4需搭配CUDA 10.0?2&#xff0c;而較新的OpenCV 4.8.0需使用更高版本CUDA?。 需注意部分模塊&#xff08;…

WPF從初學者到專家:實戰項目經驗分享與總結

WPF從初學者到專家&#xff1a;實戰項目經驗分享與總結 一、前言二、WPF 基礎概念與入門2.1 什么是 WPF2.2 XAML 基礎2.3 數據綁定基礎 三、第一個 WPF 項目&#xff1a;簡單的待辦事項列表3.1 項目需求分析3.2 項目搭建與界面設計3.3 業務邏輯實現 四、中級項目&#xff1a;音…