怎麼正確使用鎖?

来源: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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...