最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解解Spring Boot高并發(fā)鎖的使用方法

 更新時間:2025年08月13日 09:56:36   作者:蹦跑的蝸牛  
在高并發(fā)場景中,多個線程/用戶會同時操作同一共享資源,如果不做控制,會導致數(shù)據(jù)錯誤,鎖是解決這類問題的核心工具之一,下面就來介紹一下Spring Boot高并發(fā)鎖的使用

在高并發(fā)場景中(比如電商秒殺、搶票系統(tǒng)、轉(zhuǎn)賬交易),多個線程/用戶會同時操作同一共享資源(如庫存、賬戶余額、訂單號)。如果不做控制,會導致數(shù)據(jù)錯誤(如庫存超賣、余額負數(shù))、業(yè)務(wù)邏輯混亂(如重復下單)。鎖(Lock)是解決這類問題的核心工具之一。

一、概述:為什么高并發(fā)下需要鎖?

1. 高并發(fā)的“數(shù)據(jù)競爭”問題

當多個線程同時修改同一個共享資源時(如數(shù)據(jù)庫的庫存字段、內(nèi)存中的緩存值),如果沒有控制,會出現(xiàn)“數(shù)據(jù)不一致”。例如:

  • 電商場景:商品庫存剩余10件,用戶A和用戶B同時下單,兩個線程同時讀取到庫存為10,都扣減1后寫回9,最終庫存變成9(實際應(yīng)賣出2件,庫存應(yīng)為8)。
  • 轉(zhuǎn)賬場景:用戶賬戶余額100元,同時發(fā)起兩筆50元轉(zhuǎn)賬,兩個線程都讀到余額100,都扣減50后寫回50,最終余額變成50(實際應(yīng)扣減100,余額0)。

2. 鎖的核心作用

鎖是一種“互斥機制”,保證同一時刻只有一個線程能操作共享資源,避免數(shù)據(jù)競爭。類比現(xiàn)實中的“公共衛(wèi)生間”:鎖門后,其他人必須等待,直到當前用戶釋放鎖(開門)。

二、鎖的類型與適用場景

在Spring Boot中,常用的鎖分為3類,需根據(jù)業(yè)務(wù)場景選擇:

鎖類型實現(xiàn)方式適用場景優(yōu)點缺點
JVM內(nèi)置鎖synchronized關(guān)鍵字單體應(yīng)用(單進程)的小范圍并發(fā)代碼簡單,JVM自動管理鎖無法跨進程(分布式場景無效)
JUC顯式鎖ReentrantLock(Lock接口)單體應(yīng)用需要靈活控制鎖(如超時、可中斷)支持超時、可中斷、公平鎖需要手動釋放鎖(否則死鎖)
分布式鎖Redis(Redisson)、ZooKeeper分布式系統(tǒng)(多進程/多服務(wù)器)的并發(fā)跨進程協(xié)調(diào),全局唯一依賴外部組件(如Redis),有性能開銷

三、鎖的具體使用與代碼實現(xiàn)

場景說明:模擬“電商庫存扣減”

需求:用戶下單時扣減商品庫存,要求高并發(fā)下庫存不能超賣(庫存≥0)。
假設(shè)商品ID為1001,初始庫存10件。

1. JVM內(nèi)置鎖:synchronized

適用于單體應(yīng)用(只有1個Spring Boot實例),代碼簡單,JVM自動加鎖/釋放。

@Service
public class StockService {
    // 模擬數(shù)據(jù)庫中的庫存(實際開發(fā)中用數(shù)據(jù)庫或緩存)
    private int stock = 10;

    // 下單扣減庫存(synchronized保證同一時刻只有1個線程執(zhí)行)
    public synchronized boolean deductStock(int productId, int count) {
        // 檢查庫存是否足夠
        if (stock < count) {
            return false; // 庫存不足
        }
        // 模擬業(yè)務(wù)耗時(如查詢數(shù)據(jù)庫、記錄日志)
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 扣減庫存
        stock -= count;
        System.out.println("扣減成功,剩余庫存:" + stock);
        return true;
    }
}

關(guān)鍵說明
  • synchronized修飾方法時,鎖的是當前對象(this);若修飾靜態(tài)方法,鎖的是類(StockService.class)。
  • 缺點:無法跨進程(如果部署多個Spring Boot實例,每個實例的stock是獨立的,鎖無效)。

2. JUC顯式鎖:ReentrantLock

適用于單體應(yīng)用,但需要更靈活的鎖控制(如設(shè)置超時、可中斷)。

@Service
public class StockService {
    private int stock = 10;
    // 顯式鎖(可重入鎖,支持公平/非公平)
    private final ReentrantLock lock = new ReentrantLock();

    public boolean deductStock(int productId, int count) {
        // 嘗試加鎖(最多等待2秒,避免死鎖)
        try {
            if (lock.tryLock(2, TimeUnit.SECONDS)) {
                if (stock >= count) {
                    Thread.sleep(100); // 模擬業(yè)務(wù)耗時
                    stock -= count;
                    System.out.println("扣減成功,剩余庫存:" + stock);
                    return true;
                } else {
                    System.out.println("庫存不足");
                    return false;
                }
            } else {
                System.out.println("獲取鎖超時");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 必須在finally中釋放鎖(避免異常導致鎖未釋放)
            lock.unlock();
        }
    }
}

關(guān)鍵說明
  • tryLock(timeout, unit):嘗試加鎖,超時未獲取則放棄(避免線程無限等待)。
  • finally中釋放鎖:必須手動釋放,否則其他線程永遠無法獲取鎖(死鎖)。
  • 優(yōu)點:比synchronized靈活(支持超時、可中斷),適合復雜業(yè)務(wù)邏輯。

3. 分布式鎖:Redisson(基于Redis)

適用于分布式系統(tǒng)(多個Spring Boot實例部署),解決跨進程的并發(fā)問題。

@Service
public class StockService {
    @Autowired
    private RedissonClient redissonClient;

    // 模擬數(shù)據(jù)庫庫存(實際用數(shù)據(jù)庫或緩存,如Redis存儲庫存)
    private int stock = 10;

    public boolean deductStock(int productId, int count) {
        // 定義鎖的名稱(按商品ID隔離,不同商品用不同鎖)
        String lockKey = "lock:product:" + productId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 加鎖(自動續(xù)期,防止業(yè)務(wù)耗時過長鎖過期)
            // waitTime: 等待鎖的最大時間(5秒)
            // leaseTime: 鎖自動釋放時間(30秒,防止死鎖)
            boolean locked = lock.tryLock(5, 30, TimeUnit.SECONDS);
            if (!locked) {
                System.out.println("獲取鎖失敗,稍后再試");
                return false;
            }

            // 檢查并扣減庫存
            if (stock >= count) {
                Thread.sleep(100); // 模擬業(yè)務(wù)耗時
                stock -= count;
                System.out.println("扣減成功,剩余庫存:" + stock);
                return true;
            } else {
                System.out.println("庫存不足");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 釋放鎖(只有自己加的鎖才能釋放)
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
關(guān)鍵說明
  • 鎖名稱:用lock:product:1001隔離不同商品,避免不同商品的庫存操作互相阻塞。
  • 自動續(xù)期:Redisson默認會為鎖“續(xù)期”(每10秒續(xù)30秒),防止業(yè)務(wù)邏輯未執(zhí)行完鎖就過期(比如扣庫存需要20秒,鎖30秒過期,續(xù)期避免提前釋放)。
  • 分布式場景有效性:多個Spring Boot實例通過Redis的lockKey協(xié)調(diào),同一時刻只有1個實例能獲取鎖,避免跨進程的庫存超賣。

四、實際業(yè)務(wù)舉例:電商秒殺場景

場景描述

某商品開啟秒殺(庫存100件),1000個用戶同時點擊“立即購買”,需要保證:

  • 只有前100個用戶能成功購買(庫存不超賣)。
  • 后續(xù)用戶提示“已售罄”。

解決方案(分布式鎖)

  1. 用戶點擊下單時,先通過Redisson獲取該商品的分布式鎖(lock:seckill:productId)。
  2. 獲得鎖的線程檢查庫存是否足夠(stock > 0)。
  3. 庫存足夠則扣減庫存,生成訂單;否則返回“已售罄”。
  4. 釋放鎖,讓其他線程繼續(xù)競爭。

關(guān)鍵點

  • 鎖粒度:按商品ID加鎖(如lock:seckill:1001),不同商品的秒殺互不影響,提升并發(fā)效率。
  • 防死鎖:設(shè)置鎖的自動釋放時間(如30秒),即使業(yè)務(wù)異常未釋放鎖,鎖也會自動過期。
  • 性能優(yōu)化:庫存可存儲在Redis中(GET/SET操作比數(shù)據(jù)庫快),減少數(shù)據(jù)庫壓力。

五、總結(jié)

1. 鎖的選擇原則

  • 單體應(yīng)用:優(yōu)先用synchronized(簡單)或ReentrantLock(需要靈活控制)。
  • 分布式系統(tǒng):必須用分布式鎖(如Redisson),避免跨進程數(shù)據(jù)競爭。

2. 注意事項

  • 鎖粒度:盡量縮小鎖的范圍(只鎖共享資源的操作代碼),避免“鎖整個方法”降低性能。
  • 防死鎖:設(shè)置鎖的超時時間(如tryLock(5, 30, TimeUnit.SECONDS)),避免線程無限等待。
  • 性能權(quán)衡:鎖會降低并發(fā)吞吐量(同一時刻只有1個線程操作),需結(jié)合業(yè)務(wù)場景(如秒殺允許少量延遲)。

3. 擴展思考

  • 無鎖方案:對于簡單計數(shù)(如訪問量),可用AtomicInteger(基于CAS無鎖操作),但無法解決復雜業(yè)務(wù)邏輯(如庫存扣減+訂單生成)。
  • 讀寫鎖:讀多寫少場景(如商品詳情頁緩存),可用ReentrantReadWriteLock(允許多個讀鎖并發(fā),寫鎖互斥)。

到此這篇關(guān)于詳解解Spring Boot高并發(fā)鎖的使用方法的文章就介紹到這了,更多相關(guān)Spring Boot高并發(fā)鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • 一文詳解Maven的setting文件

    一文詳解Maven的setting文件

    maven?是目前java?常見的一款包管理工具,通過?maven?我們可以很方便的對項目進行編譯、打包、部署等操作,本文將詳細帶大家了解一下Maven?setting文件,需要的朋友可以參考下
    2024-02-02
  • SpringBoot種如何使用?EasyExcel?實現(xiàn)自定義表頭導出并實現(xiàn)數(shù)據(jù)格式化轉(zhuǎn)換

    SpringBoot種如何使用?EasyExcel?實現(xiàn)自定義表頭導出并實現(xiàn)數(shù)據(jù)格式化轉(zhuǎn)換

    本文詳細介紹了如何使用EasyExcel工具類實現(xiàn)自定義表頭導出,并實現(xiàn)數(shù)據(jù)格式化轉(zhuǎn)換與添加下拉框操作,通過示例和代碼,展示了如何處理不同數(shù)據(jù)結(jié)構(gòu)和注解,確保數(shù)據(jù)在導出時能夠正確顯示和格式化,此外,還介紹了如何解決特定數(shù)據(jù)類型的轉(zhuǎn)換問題,并提供了解決方案
    2024-11-11
  • Java Map 按照Value排序的實現(xiàn)方法

    Java Map 按照Value排序的實現(xiàn)方法

    Map是鍵值對的集合接口,它的實現(xiàn)類主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。這篇文章主要介紹了Java Map 按照Value排序的實現(xiàn)方法,需要的朋友可以參考下
    2016-08-08
  • Spring boot 無法注入service問題

    Spring boot 無法注入service問題

    這篇文章主要介紹了Spring boot 無法注入service問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java之哈夫曼壓縮原理案例講解

    Java之哈夫曼壓縮原理案例講解

    這篇文章主要介紹了Java之哈夫曼壓縮原理案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java效率提升神器jOOR

    Java效率提升神器jOOR

    這篇文章主要介紹了Java效率提升神器jOOR,jOOR是一個第三方庫,通過鏈式DSL接口,簡化了反射過程,更多相關(guān)內(nèi)容組要的朋友可以參考一下
    2022-07-07
  • java隨機生成10位數(shù)的字符串ID

    java隨機生成10位數(shù)的字符串ID

    這篇文章主要為大家詳細介紹了java隨機生成10位數(shù)字符串ID的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • SpringBoot中ApplicationEvent的使用步驟詳解

    SpringBoot中ApplicationEvent的使用步驟詳解

    ApplicationEvent類似于MQ,是Spring提供的一種發(fā)布訂閱模式的事件處理方式,本文給大家介紹SpringBoot中ApplicationEvent的使用步驟詳解,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Mybatis接口式編程的原理

    Mybatis接口式編程的原理

    mybatis有兩種實現(xiàn)方式,一種可以通過xml配置文件實現(xiàn),其二是面向接口編程的實現(xiàn)。本文重點給大家介紹mybatis接口編程的原理,需要的的朋友參考下
    2017-03-03
  • 基于redis key占用內(nèi)存量分析

    基于redis key占用內(nèi)存量分析

    這篇文章主要介紹了基于redis key占用內(nèi)存量分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11

最新評論

松潘县| 兰西县| 彭州市| 广州市| 莆田市| 麻栗坡县| 衡阳市| 观塘区| 平和县| 麻江县| 边坝县| 拉萨市| 高密市| 佛山市| 成安县| 张家川| 北辰区| 商洛市| 孟州市| 长岭县| 丘北县| 高要市| 诸城市| 济南市| 武功县| 镇沅| 兴和县| 四川省| 武城县| 清水县| 舒城县| 渝中区| 大悟县| 玉门市| 石景山区| 安徽省| 茶陵县| 班戈县| 襄城县| 如东县| 永济市|