怎麼正確使用鎖?

来源:https://www.cnblogs.com/wing011203/archive/2023/03/18/17229582.html
-Advertisement-
Play Games

這篇文章主要關註分散式鎖,包括加鎖和解鎖的過程,鎖的用法,加鎖帶來的代價,對性能的影響以及如何避免死鎖。 ...


鎖的原理:任何時間都只能有一個線程持有鎖,只有持有鎖的線程才能訪問被鎖保護的資源。

我們接下來看一下在鎖的使用上有什麼最佳實踐。

避免濫用鎖

如果能不用鎖,就不用鎖;如果你不確定是不是應該用鎖,那也不要鎖。

使用鎖後帶來的代價:

  1. 加鎖和解鎖過程都需要CPU時間的,這是一個性能的損失。使用鎖還可能導致線程等待鎖,等待鎖過程中的線程是阻塞狀態,過多的鎖等待會顯著降低程式的性能。
  2. 如果對鎖使用不當,很容易造成死鎖,導致整個程式“卡死”,這是非常嚴重的問題。

我們不可以看到一個共用數據,在沒有搞清楚它在併發環境中是否會出現爭用問題,就“為了保險,給它加個鎖吧。”,千萬不要有這種不負責任的想法,否則你將會付出慘痛的代價。

只有在併發環境中,共用資源不支持併發訪問,或者說併發訪問共用資源會導致系統錯誤的情況下,才需要使用鎖。

鎖的用法

使用鎖的過程可以分為三步:

  1. 在訪問共用資源之前,先獲取鎖。
  2. 如果獲取鎖成功,就可以訪問共用資源了。
  3. 使用完共用資源後釋放鎖,以便其他線程繼續訪問共用資源。

我們在使用鎖的過程中,需要註意使用完鎖,一定要釋放它。我們需要考慮到代碼可能走到的所有正常和異常的分支,確保所有情況下,鎖都能被釋放。

死鎖

死鎖是指由於某種原因,鎖一直沒有釋放,後續需要獲取鎖的線程都將處於等解鎖狀態。

大部分編程語言都提供了可重入鎖,如果沒有特別的需求,我們也要儘量使用可重入鎖。

下麵是幾條如何避免死鎖的建議:

  1. 避免濫用鎖。
  2. 對於同一把鎖,加鎖和解鎖必須要放在同一個方法中,這樣一次加鎖對應一次解鎖,代碼清晰簡單,便於分析問題。
  3. 儘量避免在持有一把鎖的情況下,去獲取另外一把鎖,就是要儘量避免同時持有多把鎖。
  4. 如果需要持有多把鎖,一定要註意加解鎖的順序,解鎖的順序要和加鎖的殊勛想法,比如,獲取三把鎖的順序是A、B、C,釋放鎖的順序必須是C、B、A。

使用讀寫鎖兼顧性能和安全

對於共用數據,如果我們的方法只是去讀取它,而不會修改,也是需要加鎖的,因為有可能在讀取數據的過程中,有其他線程會更新數據。

但如果只是簡單地為數據加一個鎖,對於“讀多寫少”的場景,性能會受到影響。針對數據的讀寫操作,我們希望能夠做到:1)讀操作可以併發執行,2)寫的同時不能併發讀,也不能併發寫。

Java中的ReadWriteLock可以用來解決這個問題,看下麵的代碼框架:


ReadWriteLock rwlock = new ReentrantReadWriteLock();

public void read() {
  rwlock.readLock().lock();
  try {
    // 在這兒讀取共用數據
  } finally {
    rwlock.readLock().unlock();
  }
}
public void write() {
  rwlock.writeLock().lock();
  try {
    // 在這兒更新共用數據
  } finally {
    rwlock.writeLock().unlock();
  }
}

在這段代碼中,需要讀數據的時候,我們獲取鎖,這個鎖不是一個互斥鎖,即read()方法可以支持多個線程並行執行,從而保證數據的讀性能。寫數據的時候,我們獲得寫鎖,這是一個互斥鎖,當一個線程持有寫鎖的時候,其他線程既無法獲得讀鎖,也無法獲得寫鎖,從而達到了保護數據的目的。

    作者:李潘     出處:http://wing011203.cnblogs.com/     本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前騰訊工程師,經歷過大廠,也經歷過創業! 我已奔四,但我還在持續學習,持續成長! 我非常樂意把我的經驗和心得分享給你! 我是阿銘,關註我,和我一起成長為技術大牛! ↓↓↓↓↓ 關於DevOps這個概念,可能100個人能給出100個說法,這是因為每個人所接觸到的環境有所差異,不同的公司要解決的問題自然 ...
  • 案例現象 這天,監控系統發來一條告警消息,內容說某台伺服器根目錄磁碟占用空間達到閾值,超過百分之八十了 登上伺服器,df -Th 看一下,發現磁碟空間確實不夠用了 進入到根目錄,然後 du -sh * 可以看到,var 目錄下的磁碟空間已經占用了 75G 既然如此,刪除 var 目錄下一些占空間較大 ...
  • reactive reactive 創建一個深層的對象的響應式代理,即對象根屬性以及嵌套對象的屬性都是響應式的。如果使用 ES6 結構賦值,就會使得這個對象的響應式代理第一層(根屬性)屬性失去響應式,但其嵌套下的對象屬性還是響應式的。 shallowReactive 會創建淺層的對象的響應式代理,只 ...
  • 1 前言 最近有個需求,需要使用JS快速讀取外部大數據文件(60w條記錄的表)。筆者嘗試過使用JS讀取Excel文件,但是跑了十幾分鐘仍未出結果,後來筆者嘗試將原數據保存為TXT文件,再從TXT文件中讀取數據,只需幾秒鐘即可讀取完畢。在此分享一下,也留著以後備用。 2 案例 為方便快速理解,筆者挑選 ...
  • 前端常見的十種佈局方式 作為一個開發小白,也是第一次編寫博客文章,若有錯誤請各位大牛大佬指正,輕噴!!! 我在學校接觸最多的就是前端,然後最近在學習新的前端知識,發現前端佈局常見的有很多種,不同的應用場景有不同的佈局方式,下麵就來簡單介紹一下吧。 靜態佈局 浮動佈局 定位佈局 柵格佈局 table布 ...
  • 此內容包含: html基礎 列表、表格 媒體元素 表單(重點) 1、HTML 基礎 目標: 會使用HTML5的基本結構創建網頁 會使用文本相關標簽排版文本信息 會使用圖像相關標簽實現圖文並茂的頁面 會使用標簽創建超鏈接、錨鏈接及功能性鏈接 1.1、什麼是HTML HTML:Hyper Text Ma ...
  • 定義 如果希望動態給某個類添加一些屬性或者方法,但是你又不希望這個類派生的對象受到影響,那麼裝飾器模式就可以給你帶來這樣的體驗。 它的定義就是在不改變原對象的基礎上,通過對其進行包裝拓展,使得原有對象可以動態具有更多功能,從而滿足用戶的更複雜需求。 舉個例子,一部手機,你可以買各種花里胡哨的手機殼等 ...
  • MVVM M:模型(Model):data V:視圖(View):模板 VM:視圖模型(ViewModel):Vue實例對象 Vue收到了MVVM模型的啟發,MVVM是vue實現數據驅動視圖和雙向數據綁定的核心原理,通過ViewModel監聽DOM和數據源的變化。 Object.defineProp ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...