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

Java實現(xiàn)分布式鎖的3種方法總結(jié)

 更新時間:2023年09月13日 10:13:16   作者:Java中文社群  
分布式鎖是一種用于保證分布式系統(tǒng)中多個進程或線程同步訪問共享資源的技術(shù),同時它又是面試中的常見問題,所以我們本文就重點來看分布式鎖的具體實現(xiàn),希望對大家有所幫助

分布式鎖是一種用于保證分布式系統(tǒng)中多個進程或線程同步訪問共享資源的技術(shù)。同時它又是面試中的常見問題,所以我們本文就重點來看分布式鎖的具體實現(xiàn)(含實現(xiàn)代碼)。

在分布式系統(tǒng)中,由于各個節(jié)點之間的網(wǎng)絡(luò)通信延遲、故障等原因,可能會導(dǎo)致數(shù)據(jù)不一致的問題。分布式鎖通過協(xié)調(diào)多個節(jié)點的行為,保證在任何時刻只有一個節(jié)點可以訪問共享資源,以避免數(shù)據(jù)的不一致性和沖突。

1.分布式鎖要求

分布式鎖通常需要滿足以下幾個要求:

  • 互斥性:在任意時刻只能有一個客戶端持有鎖。
  • 不會發(fā)生死鎖:即使持有鎖的客戶端發(fā)生故障,也能保證鎖最終會被釋放。
  • 具有容錯性:分布式鎖需要能夠容忍節(jié)點故障等異常情況,保證系統(tǒng)的穩(wěn)定性。

2.實現(xiàn)方案

在 Java 中,實現(xiàn)分布式鎖的方案有多種,包括:

  • 基于數(shù)據(jù)庫實現(xiàn)的分布式鎖:可以通過數(shù)據(jù)庫的樂觀鎖或悲觀鎖實現(xiàn)分布式鎖,但是由于數(shù)據(jù)庫的 IO 操作比較慢,不適合高并發(fā)場景。
  • 基于 ZooKeeper 實現(xiàn)的分布式鎖:ZooKeeper 是一個高可用性的分布式協(xié)調(diào)服務(wù),可以通過它來實現(xiàn)分布式鎖。但是使用 ZooKeeper 需要部署額外的服務(wù),增加了系統(tǒng)復(fù)雜度。
  • 基于 Redis 實現(xiàn)的分布式鎖:Redis 是一個高性能的內(nèi)存數(shù)據(jù)庫,支持分布式部署,可以通過Redis的原子操作實現(xiàn)分布式鎖,而且具有高性能和高可用性。

3.數(shù)據(jù)庫分布式鎖

數(shù)據(jù)庫的樂觀鎖或悲觀鎖都可以實現(xiàn)分布式鎖,下面分別來看。

3.1 悲觀鎖

在數(shù)據(jù)庫中使用 for update 關(guān)鍵字可以實現(xiàn)悲觀鎖,我們在 Mapper 中添加 for update 即可對數(shù)據(jù)加鎖,實現(xiàn)代碼如下:

<!--?UserMapper.xml?-->
<select?id="selectByIdForUpdate"?resultType="User">
????SELECT?*?FROM?user?WHERE?id?=?#{id}?FOR?UPDATE
</select>

在 Service 中調(diào)用 Mapper 方法,即可獲取到加鎖的數(shù)據(jù):

@Transactional
public?void?updateWithPessimisticLock(int?id,?String?name)?{
????User?user?=?userMapper.selectByIdForUpdate(id);
????if?(user?!=?null)?{
????????user.setName(name);
????????userMapper.update(user);
????}?else?{
????????throw?new?RuntimeException("數(shù)據(jù)不存在");
????}
}

3.2 樂觀鎖

在 MyBatis 中,可以通過給表添加一個版本號字段來實現(xiàn)樂觀鎖。在 Mapper 中,使用標簽定義更新語句,同時使用 set 標簽設(shè)置版本號的增量。

<!--?UserMapper.xml?-->
<update?id="updateWithOptimisticLock">
????UPDATE?user?SET
????name?=?#{name},
????version?=?version?+?1
????WHERE?id?=?#{id}?AND?version?=?#{version}
</update>

在 Service 中調(diào)用 Mapper 方法,需要傳入更新數(shù)據(jù)的版本號。如果更新失敗,說明數(shù)據(jù)已經(jīng)被其他事務(wù)修改,具體實現(xiàn)代碼如下:

@Transactional
public?void?updateWithOptimisticLock(int?id,?String?name,?int?version)?{
????User?user?=?userMapper.selectById(id);
????if?(user?!=?null)?{
????????user.setName(name);
????????user.setVersion(version);
????????int?rows?=?userMapper.updateWithOptimisticLock(user);
????????if?(rows?==?0)?{
????????????throw?new?RuntimeException("數(shù)據(jù)已被其他事務(wù)修改");
????????}
????}?else?{
????????throw?new?RuntimeException("數(shù)據(jù)不存在");
????}
}

4.Zookeeper 分布式鎖

在 Spring Boot 中,可以使用 Curator 框架來實現(xiàn) ZooKeeper 分布式鎖,具體實現(xiàn)分為以下 3 步:

  • 引入 Curator 和 ZooKeeper 客戶端依賴;
  • 配置 ZooKeeper 連接信息;
  • 編寫分布式鎖實現(xiàn)類。

4.1 引入 Curator 和 ZooKeeper

<dependency>
????<groupId>org.apache.curator</groupId>
????<artifactId>curator-framework</artifactId>
????<version>latest</version>
</dependency>
<dependency>
????<groupId>org.apache.curator</groupId>
????<artifactId>curator-recipes</artifactId>
????<version>latest</version>
</dependency>
<dependency>
????<groupId>org.apache.zookeeper</groupId>
????<artifactId>zookeeper</artifactId>
????<version>latest</version>
</dependency>

4.2 配置 ZooKeeper 連接

在 application.yml 中添加 ZooKeeper 連接配置:

spring:
??zookeeper:
????connect-string:?localhost:2181
????namespace:?demo

4.3 編寫分布式鎖實現(xiàn)類

@Component
public?class?DistributedLock?{
????@Autowired
????private?CuratorFramework?curatorFramework;
????/**
?????*?獲取分布式鎖
?????*
?????*?@param?lockPath???鎖路徑
?????*?@param?waitTime???等待時間
?????*?@param?leaseTime??鎖持有時間
?????*?@param?timeUnit???時間單位
?????*?@return?鎖對象
?????*?@throws?Exception?獲取鎖異常
?????*/
????public?InterProcessMutex?acquire(String?lockPath,?long?waitTime,?long?leaseTime,?TimeUnit?timeUnit)?throws?Exception?{
????????InterProcessMutex?lock?=?new?InterProcessMutex(curatorFramework,?lockPath);
????????if?(!lock.acquire(waitTime,?timeUnit))?{
????????????throw?new?RuntimeException("獲取分布式鎖失敗");
????????}
????????if?(leaseTime?>?0)?{
????????????lock.acquire(leaseTime,?timeUnit);
????????}
????????return?lock;
????}
????/**
?????*?釋放分布式鎖
?????*
?????*?@param?lock?鎖對象
?????*?@throws?Exception?釋放鎖異常
?????*/
????public?void?release(InterProcessMutex?lock)?throws?Exception?{
????????if?(lock?!=?null)?{
????????????lock.release();
????????}
????}
}

5.Redis 分布式鎖

我們可以使用 Redis 客戶端 Redisson 實現(xiàn)分布式鎖,它的實現(xiàn)步驟如下:

  • 添加 Redisson 依賴
  • 配置 Redisson 連接信息
  • 編寫分布式鎖代碼類

5.1 添加 Redisson 依賴

在 pom.xml 中添加如下配置:

<!--?https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter?-->
<dependency>
????<groupId>org.redisson</groupId>
????<artifactId>redisson-spring-boot-starter</artifactId>
????<version>3.20.0</version>
</dependency>

5.2 配置 Redisson 連接

在 Spring Boot 項目的配置文件 application.yml 中添加 Redisson 配置:

spring:
??data:
????redis:
??????host:?localhost
??????port:?6379
??????database:?0
redisson:
??codec:?org.redisson.codec.JsonJacksonCodec
??single-server-config:
????address:?"redis://${spring.data.redis.host}:${spring.redis.port}"
????database:?"${spring.data.redis.database}"
????password:?"${spring.data.redis.password}"

5.3 編寫分布式鎖代碼類

import?jakarta.annotation.Resource;
import?org.redisson.Redisson;
import?org.redisson.api.RLock;
import?org.springframework.stereotype.Service;
import?java.util.concurrent.TimeUnit;
@Service
public?class?RedissonLockService?{
????@Resource
????private?Redisson?redisson;
????/**
?????*?加鎖
?????*
?????*?@param?key?????分布式鎖的?key
?????*?@param?timeout?超時時間
?????*?@param?unit????時間單位
?????*?@return
?????*/
????public?boolean?tryLock(String?key,?long?timeout,?TimeUnit?unit)?{
????????RLock?lock?=?redisson.getLock(key);
????????try?{
????????????return?lock.tryLock(timeout,?unit);
????????}?catch?(InterruptedException?e)?{
????????????Thread.currentThread().interrupt();
????????????return?false;
????????}
????}
????/**
?????*?釋放分布式鎖
?????*
?????*?@param?key?分布式鎖的?key
?????*/
????public?void?unlock(String?key)?{
????????RLock?lock?=?redisson.getLock(key);
????????lock.unlock();
????}
}

6.Redis VS Zookeeper

Redis 和 ZooKeeper 都可以用來實現(xiàn)分布式鎖,它們在實現(xiàn)分布式鎖的機制和原理上有所不同,具體區(qū)別如下:

  • 數(shù)據(jù)存儲方式:Redis 將鎖信息存儲在內(nèi)存中,而 ZooKeeper 將鎖信息存儲在 ZooKeeper 的節(jié)點上,因此 ZooKeeper 需要更多的磁盤空間。
  • 鎖的釋放:Redis 的鎖是通過設(shè)置鎖的過期時間來自動釋放的,而 ZooKeeper 的鎖需要手動釋放,如果鎖的持有者出現(xiàn)宕機或網(wǎng)絡(luò)中斷等情況,需要等待鎖的超時時間才能自動釋放。
  • 鎖的競爭機制:Redis 使用的是單機鎖,即所有請求都直接連接到同一臺 Redis 服務(wù)器,容易發(fā)生單點故障;而 ZooKeeper 使用的是分布式鎖,即所有請求都連接到 ZooKeeper 集群,具有較好的可用性和可擴展性。
  • 一致性:Redis 的鎖是非嚴格意義下的分布式鎖,因為在多臺機器上運行多個進程時,由于 Redis 的主從同步可能會存在數(shù)據(jù)不一致的問題;而 ZooKeeper 是強一致性的分布式系統(tǒng),保證了數(shù)據(jù)的一致性。
  • 性能:Redis 的性能比 ZooKeeper 更高,因為 Redis 將鎖信息存儲在內(nèi)存中,而 ZooKeeper 需要進行磁盤讀寫操作。

總之,Redis 適合實現(xiàn)簡單的分布式鎖場景,而 ZooKeeper 適合實現(xiàn)復(fù)雜的分布式協(xié)調(diào)場景,也就是 ZooKeeper 適合強一致性的分布式系統(tǒng)。

強一致性是指系統(tǒng)中的所有節(jié)點在任何時刻看到的數(shù)據(jù)都是一致的。ZooKeeper 中的數(shù)據(jù)是有序的樹形結(jié)構(gòu),每個節(jié)點都有唯一的路徑標識符,所有節(jié)點都共享同一份數(shù)據(jù),當任何一個節(jié)點對數(shù)據(jù)進行修改時,所有節(jié)點都會收到通知,更新數(shù)據(jù),并確保數(shù)據(jù)的一致性。在 ZooKeeper 中,強一致性體現(xiàn)在數(shù)據(jù)的讀寫操作上。ZooKeeper 使用 ZAB(ZooKeeper Atomic Broadcast)協(xié)議來保證數(shù)據(jù)的一致性,該協(xié)議確保了數(shù)據(jù)更新的順序,所有的數(shù)據(jù)更新都需要經(jīng)過集群中的大多數(shù)節(jié)點確認,保證了數(shù)據(jù)的一致性和可靠性。

小結(jié)

在 Java 中,使用數(shù)據(jù)庫、ZooKeeper 和 Redis 都可以實現(xiàn)分布式鎖。但數(shù)據(jù)庫 IO 操作比較慢,不適合高并發(fā)場景;Redis 執(zhí)行效率最高,但在主從切換時,可能會出現(xiàn)鎖丟失的情況;ZooKeeper 是一個高可用性的分布式協(xié)調(diào)服務(wù),可以保證數(shù)據(jù)的強一致性,但是使用 ZooKeeper 需要部署額外的服務(wù),增加了系統(tǒng)復(fù)雜度。所以沒有最好的解決方案,只有最合適自己的解決方案。

以上就是Java實現(xiàn)分布式鎖的3種方法總結(jié)的詳細內(nèi)容,更多關(guān)于Java分布式鎖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 關(guān)于SpringBoot配置文件application.properties的路徑問題

    關(guān)于SpringBoot配置文件application.properties的路徑問題

    這篇文章主要介紹了關(guān)于SpringBoot配置文件application.properties的路徑問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Exception in thread main java.lang.NoClassDefFoundError錯誤解決方法

    Exception in thread main java.lang.NoClassDefFoundError錯誤解決方

    這篇文章主要介紹了Exception in thread main java.lang.NoClassDefFoundError錯誤解決方法,需要的朋友可以參考下
    2016-08-08
  • Java入門之繼承多態(tài)使用及說明

    Java入門之繼承多態(tài)使用及說明

    文章概述Java繼承與多態(tài)的核心概念,包括繼承的共性抽取、子類父類關(guān)系、super關(guān)鍵字的使用、構(gòu)造方法與代碼塊執(zhí)行順序,以及向上轉(zhuǎn)型、動態(tài)綁定和重寫機制,最后預(yù)告多態(tài)內(nèi)容并附練習(xí)題
    2025-09-09
  • Spring??AOP的兩種使用方法

    Spring??AOP的兩種使用方法

    這篇文章主要介紹了Spring?AOP的兩種使用方法,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • Java 中的 getDeclaredMethods() 方法(使用與原理)

    Java 中的 getDeclaredMethods() 方法(使用與原理)

    文章介紹了Java反射機制中的`getDeclaredMethods()`方法,詳細講解了其使用方法、原理、注意事項以及實際應(yīng)用場景,幫助讀者更好地理解和應(yīng)用這一強大的工具,感興趣的朋友一起看看吧
    2024-12-12
  • MybatisPlus自動生成代碼的實現(xiàn)示例

    MybatisPlus自動生成代碼的實現(xiàn)示例

    本文主要介紹了MybatisPlus-自動生成代碼,代碼生成器可以自動生成Mapper、Service、PO等代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-12-12
  • Java編寫實現(xiàn)窗體程序顯示日歷

    Java編寫實現(xiàn)窗體程序顯示日歷

    這篇文章主要為大家詳細介紹了Java編寫實現(xiàn)窗體程序顯示日歷,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Jenkins發(fā)送測試報告郵件過程詳解

    Jenkins發(fā)送測試報告郵件過程詳解

    這篇文章主要介紹了Jenkins發(fā)送測試報告郵件過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • 使用svn管理Maven項目的方法步驟

    使用svn管理Maven項目的方法步驟

    這篇文章主要介紹了使用svn管理Maven項目的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java線程池配置的一些常見誤區(qū)總結(jié)

    Java線程池配置的一些常見誤區(qū)總結(jié)

    這篇文章主要給大家介紹了關(guān)于Java線程池配置的一些常見誤區(qū),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評論

新巴尔虎左旗| 遂宁市| 剑河县| 盖州市| 宿州市| 南木林县| 宿松县| 个旧市| 平定县| 大竹县| 渭源县| 库车县| 曲麻莱县| 翁牛特旗| 康保县| 浦县| 旺苍县| 洞头县| 松阳县| 汤原县| 施秉县| 孝昌县| 晋江市| 天水市| 平安县| 武鸣县| 芦溪县| 富蕴县| 芦山县| 安塞县| 蚌埠市| 延津县| 龙胜| 湖州市| 华蓥市| 化州市| 锡林郭勒盟| 长子县| 太仓市| 筠连县| 大邑县|