樂觀鎖?悲觀鎖? 這篇文章告訴你該怎麼選擇

来源:https://www.cnblogs.com/cxydmx/archive/2019/11/05/11802353.html
-Advertisement-
Play Games

1. 樂觀鎖 樂觀鎖顧名思義就是在操作時很樂觀,認為操作不會產生併發問題(不會有其他線程對數據進行修改),因此不會上鎖。但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制或CAS(compare and swap)演算法實現。簡單理解:這裡的數據,別想太多,你儘管用,出問題了 ...


1. 樂觀鎖

樂觀鎖顧名思義就是在操作時很樂觀,認為操作不會產生併發問題(不會有其他線程對數據進行修改),因此不會上鎖。但是在更新時會判斷其他線程在這之前有沒有對數據進行修改,一般會使用版本號機制CAS(compare and swap)演算法實現。
簡單理解:這裡的數據,別想太多,你儘管用,出問題了算我慫,即操作失敗後事務回滾、提示。版本號、CAS這2種方法本質上是一樣的:假如滿足條件,做你想做的事,條件判斷是原子的或者是快速的,耗時幾乎不計。

1.1 版本號機制

1.1.1 實現套路:

  • 取出記錄時,獲取當前version
  • 更新時,帶上這個version
  • 執行更新時, set version = newVersion where version = oldVersion
  • 如果version不對,就更新失敗

核心SQL:

update table set name = 'Aron', version = version + 1 where id = #{id} and version = #{version};

1.1.2 實例-Mybatis-plus 樂觀鎖實現

原文查看請點擊 Mybatis-plus 樂觀鎖實現

1.2 CAS演算法

樂觀鎖的另一種技術技術,當多個線程嘗試使用CAS同時更新同一個變數時,只有其中一個線程能更新變數的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。

CAS 操作中包含三個操作數 :

  • 需要讀寫的記憶體位置V
  • 進行比較的預期原值A
  • 擬寫入的新值B

如果記憶體位置V的值與預期原值A相匹配,那麼處理器會自動將該位置值更新為新值B。否則處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該位置的值(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當前值)。CAS 有效地說明瞭“ 我認為位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。 ”這其實和樂觀鎖的衝突檢查+數據更新的原理是一樣的。

1.2.1 實例-concurrent包的實現

由於javaCAS同時具有 volatile 讀和volatile寫的記憶體語義,因此Java線程之間的通信現在有了下麵四種方式:

  1. A線程寫volatile變數,隨後B線程讀這個volatile變數。
  2. A線程寫volatile變數,隨後B線程用CAS更新這個volatile變數。
  3. A線程用CAS更新一個volatile變數,隨後B線程用CAS更新這個volatile變數。
  4. A線程用CAS更新一個volatile變數,隨後B線程讀這個volatile變數。

JavaCAS會使用現代處理器上提供的高效機器級別原子指令,這些原子指令以原子方式對記憶體執行讀-改-寫操作,這是在多處理器中實現同步的關鍵(從本質上來說,能夠支持原子性讀-改-寫指令的電腦器,是順序計算圖靈機的非同步等價機器,因此任何現代的多處理器都會去支持某種能對記憶體執行原子性讀-改-寫操作的原子指令)。同時,volatile變數的讀/寫和CAS可以實現線程之間的通信。把這些特性整合在一起,就形成了整個concurrent包得以實現的基石。

仔細分析concurrent包的源代碼實現,會發現一個通用化的實現模式:

  1. 首先,聲明共用變數為volatile;  
  2. 然後,使用CAS的原子條件更新來實現線程之間的同步;
  3. 同時,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的記憶體語義來實現線程

1.2.2 缺點

  • ABA問題

比如說一個線程T1從記憶體位置V中取出A,這時候另一個線程T2也從記憶體中取出A,並且T2進行了一些操作變成了B,然後T2又將V位置的數據變成A,這時候線程T1進行CAS操作發現記憶體中仍然是A,然後T1操作成功。儘管線程T1CAS操作成功,但可能存在潛藏的問題。

  • 迴圈時間長開銷大

自旋CAS(不成功,就一直迴圈執行,直到成功)如果長時間不成功,會給CPU帶來非常大的執行開銷。如果JVM能支持處理器提供的pause指令那麼效率會有一定的提升,pause指令有兩個作用,第一它可以延遲流水線執行指令(de-pipeline),使CPU不會消耗過多的執行資源,延遲的時間取決於具體實現的版本,在一些處理器上延遲時間是零。第二它可以避免在退出迴圈的時候因記憶體順序衝突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執行效率。

  • 只能保證一個共用變數的原子操作

當對一個共用變數執行操作時,我們可以使用迴圈CAS的方式來保證原子操作,但是對多個共用變數操作時,迴圈CAS就無法保證操作的原子性,這個時候就可以用鎖,或者有一個取巧的辦法,就是把多個共用變數合併成一個共用變數來操作。比如有兩個共用變數i = 2,j = a,合併一下ij = 2a,然後用CAS來操作ij。從Java 1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變數放在一個對象里來進行CAS操作。

2. 悲觀鎖

總是假設最壞的情況(想法很悲觀),每次取數據時都認為其他線程會修改,所以都會加(悲觀)鎖。一旦加鎖,不同線程同時執行時,只能有一個線程執行,其他的線程在入口處等待,直到鎖被釋放。

悲觀鎖在MySQLJava有廣泛的使用

  • MySQL的讀鎖、寫鎖、行鎖等
  • Javasynchronized關鍵字

3. 總結

讀的多,衝突幾率小,樂觀鎖。
寫的多,衝突幾率大,悲觀鎖。



關註微信公眾號【程式員的夢想】,專註於Java,SpringBoot,SpringCloud,微服務,Docker以及前後端分離等全棧技術。

在這裡插入圖片描述


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 之前同事問了一道需要點腦洞的演算法題,我覺得蠻有意思的,思路可能會給大家帶來一些啟發,特意在此記錄一下 題目 現有一個元素僅為 0,1 的 n 階矩陣,求連續相鄰(水平或垂直,不能有環)元素值為 1 的序列和的最大值 假設有如下矩陣 則此矩陣連續相鄰元素為 1 的序列和分別為 4, 3,(如圖示),可 ...
  • 2019-11-05-23:03:28 List集合: java.util.List 介面繼承自 Collection 介面,是單列集合的一個重要分支,習慣性地會將實現了List 介面的對象稱為List集合 特點: 1. 它是一個元素存取有序的集合。例如,存元素的順序是11、22、33。那麼集合中, ...
  • 1. 列表 1.1 列表的介紹 列表是python的基礎數據類型之⼀,其他編程語⾔也有類似的數據類型。比如JS中的數組, java中的數組等等。它是以[ ]括起來,每個元素⽤','隔開⽽且可以存放各種數據類型: lst = [1, '哈哈', "吼吼", [1,8,0,"百度"], ("我","叫" ...
  • 1. python介紹 1.1 python是什麼樣的語言 編程語⾔主要從以下⼏個⻆度為進⾏分類,編譯型和解釋型、靜態語⾔和動態語⾔、強類型定義語⾔和弱類型定義語⾔,我們先看編譯型語⾔和解釋型語⾔.稍後再說強類型和弱類型 編譯和解釋的區別是什麼? 編譯器是把源程式的每⼀條語句都編譯成機器語⾔,並保存 ...
  • 開發環境: Windows操作系統 開發工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 資料庫 項目簡介: 系統前段頁面採用jsp + JavaScript + css的組合技術開發,其中JavaScript使用了jQuery和bootstrap框架,這兩個前段 ...
  • 1.緩存雪崩和緩存穿透問題 1.1緩存雪崩 簡介:緩存同一時間大面積的失效,所以,後面的請求都會落到資料庫上,造成資料庫短時間內承受大量請求而崩掉。 解決辦法:  事前:儘量保證整個 redis 集群的高可用性,發現機器宕機儘快補上。選擇合適的記憶體淘汰策略。  事中:本地 ehcache 緩存 ...
  • 一、基礎類介紹 1、工作簿類Workbook簡介: import xlwt class Workbook(object0): ''' 工作簿類,使用xlwt創建excel文件時,首先要實例化此類的對象 ''' def __init__(self, encoding='ascii', style_co ...
  • 在項目開發過程中經常遇到時間處理,但是你真的用對了嗎,理解阿裡巴巴開發手冊中禁用static修飾SimpleDateFormat嗎 通過閱讀本篇文章你將瞭解到: 為什麼需要LocalDate、LocalTime、LocalDateTime【java8新提供的類】 java8新的時間API的使用方式, ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...