天天看點

在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖

2 鎖和被保護的對象是不是同一層面

梳理鎖和要保護的對象是否是同一層面的。

案例

  • 累加counter
  • 在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖
    測試
  • 在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖
  • 因為傳參運作100萬次,是以執行後應該輸出100萬,但輸出:
  • 在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖
  • why?

在非靜态的wrong方法上加鎖,隻能確定多線程無法執行同一執行個體的wrong,無法保證不執行不同執行個體的wrong。靜态counter在多執行個體是共享的,是以會出現線程安全問題。

解決方案

在類中定義一個Object類型的靜态字段,在操作counter之前對該字段加鎖。

在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖

評論裡肯定又有人會說:就這?直接把wrong定義為靜态不就行?鎖不就是類級别的了?

是可以,但不可能為解決線程安全改變代碼結構,随便把執行個體方法改為靜态方法。

3 加鎖前考慮鎖粒度和業務場景

方法上加

synchronized

加鎖是簡單,但也不能在業務代碼中濫用:

  1. 沒必要

    絕大多數業務代碼是MVC三層架構,資料經過無狀态的

    Controller=>Service=>Repository=>DB

    沒必要使用

    synchronized

    保護什麼資料。是以這也是為何很多同學笑評面試造火箭,工作擰螺絲~
  2. 大機率降低性能

使用Spring時,預設Controller、Service、Repository都是單例,加synchronized會導緻整個程式幾乎隻能支援單線程,造成極大性能問題。

即使我們确實有一些共享資源需要保護,也要盡可能減小鎖粒度。就像 concurrentHashMap 的一生發展。

業務代碼有個ArrayList會被多線程操作而需保護,但又有段比較耗時的不涉及線程安全的操作,應該如何加鎖?

推薦隻在操作ArrayList時給這ArrayList加鎖。

在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖

正确加鎖的版本幾乎是對錯誤加鎖的十倍性能。

細化鎖後,性能還無法滿足,就要考慮另一個次元的粒度問題:區分讀寫場景以及資源的通路沖突,考慮

4 悲觀鎖 V.S 樂觀鎖

一般業務代碼很少需要進一步考慮這兩種更細粒度的鎖,自己結合業務的性能需求考慮是否要繼續優化:

  1. 讀寫差異明顯場景,考慮使用

    ReentrantReadWriteLock

    讀寫鎖
  2. 若JDK版本>8、共享資源的沖突機率也沒那麼大,考慮使用

    StampedLock

    樂觀讀
  3. JDK的

    ReentrantLock

    ReentrantReadWriteLock

    都提供了公平鎖版本,在沒有明确需求情況下不要輕易開啟公平鎖,在任務很輕情況下開啟公平鎖可能會讓性能下降百倍

5 死鎖

鎖的粒度夠用就好,這意味着程式邏輯中有時會存在一些細粒度鎖。但一個業務邏輯如果涉及多鎖,就很容易産生死鎖。

在電商場景的下單流程中,需要鎖定訂單中多個商品的庫存,拿到所有商品的鎖後再進行下單扣減庫存,全部操作完成後釋放所有鎖。

上線後發現,下單失敗機率高,失敗後使用者需重新下單,極大影響使用者體驗。

案發原因

因為扣減庫存的順序不同,導緻并發下多個線程可能互相持有部分商品的鎖,又等待其他線程釋放另一部分商品的鎖,于是出現死鎖。

接下來,我們剖析一下核心的業務代碼。

首先,定義一個商品類型,包含商品名、庫存剩餘和商品的庫存鎖三個屬性,每一種商品預設庫存1000個;然後,初始化10個這樣的商品對象來模拟商品清單:

在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖

模拟在購物車進行商品選購,每次從商品清單(items字段)中随機選購三個商品(不考慮每次選購多個同類商品的邏輯,購物車中不展現商品數量):

在 web 業務開發中究竟該如何使用鎖?(中)2 鎖和被保護的對象是不是同一層面案例3 加鎖前考慮鎖粒度和業務場景4 悲觀鎖 V.S 樂觀鎖5 死鎖