欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java基于mongodb實(shí)現(xiàn)分布式鎖的示例代碼

 更新時(shí)間:2021年08月02日 15:34:48   作者:jqpeng的技術(shù)記事本  
本文主要介紹了java基于mongodb實(shí)現(xiàn)分布式鎖,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

原理

通過(guò)線(xiàn)程安全findAndModify 實(shí)現(xiàn)鎖

實(shí)現(xiàn)

定義鎖存儲(chǔ)對(duì)象:

/**
 * mongodb 分布式鎖
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "distributed-lock-doc")
public class LockDocument {
    @Id
    private String id;
    private long expireAt;
    private String token;
}

定義Lock API:

public interface LockService {

    String acquire(String key, long expiration);

    boolean release(String key, String token);

    boolean refresh(String key, String token, long expiration);
}

獲取鎖:

  @Override
    public String acquire(String key, long expiration) {
        Query query = Query.query(Criteria.where("_id").is(key));
        String token = this.generateToken();
        Update update = new Update()
            .setOnInsert("_id", key)
            .setOnInsert("expireAt", System.currentTimeMillis() + expiration)
            .setOnInsert("token", token);

        FindAndModifyOptions options = new FindAndModifyOptions().upsert(true)
                                                                 .returnNew(true);
        LockDocument doc = mongoTemplate.findAndModify(query, update, options,
                                                       LockDocument.class);
        boolean locked = doc.getToken() != null && doc.getToken().equals(token);

        // 如果已過(guò)期
        if (!locked && doc.getExpireAt() < System.currentTimeMillis()) {
            DeleteResult deleted = this.mongoTemplate.remove(
                Query.query(Criteria.where("_id").is(key)
                                    .and("token").is(doc.getToken())
                                    .and("expireAt").is(doc.getExpireAt())),
                LockDocument.class);
            if (deleted.getDeletedCount() >= 1) {
                // 成功釋放鎖, 再次嘗試獲取鎖
                return this.acquire(key, expiration);
            }
        }

        log.debug("Tried to acquire lock for key {} with token {} . Locked: {}",
                  key, token, locked);
        return locked ? token : null;
    }

原理:

  • 先嘗試upsert鎖對(duì)象,如果成功且token一致,說(shuō)明拿到鎖
  • 否則加鎖失敗
  • 如果未拿到鎖,但是鎖已過(guò)期,嘗試刪除鎖
    • 如果刪除成功,再次嘗試拿鎖
    • 如果失敗,說(shuō)明鎖可能已經(jīng)續(xù)期了

釋放和續(xù)期鎖:

   @Override
   public boolean release(String key, String token) {
       Query query = Query.query(Criteria.where("_id").is(key)
                                         .and("token").is(token));
       DeleteResult deleted = mongoTemplate.remove(query, LockDocument.class);
       boolean released = deleted.getDeletedCount() == 1;
       if (released) {
           log.debug("Remove query successfully affected 1 record for key {} with token {}",
                     key, token);
       } else if (deleted.getDeletedCount() > 0) {
           log.error("Unexpected result from release for key {} with token {}, released {}",
                     key, token, deleted);
       } else {
           log.error("Remove query did not affect any records for key {} with token {}",
                     key, token);
       }

       return released;
   }

   @Override
   public boolean refresh(String key, String token,
                          long expiration) {
       Query query = Query.query(Criteria.where("_id").is(key)
                                         .and("token").is(token));
       Update update = Update.update("expireAt",
                                     System.currentTimeMillis() + expiration);
       UpdateResult updated =
           mongoTemplate.updateFirst(query, update, LockDocument.class);

       final boolean refreshed = updated.getModifiedCount() == 1;
       if (refreshed) {
           log.debug("Refresh query successfully affected 1 record for key {} " +
                     "with token {}", key, token);
       } else if (updated.getModifiedCount() > 0) {
           log.error("Unexpected result from refresh for key {} with token {}, " +
                     "released {}", key, token, updated);
       } else {
           log.warn("Refresh query did not affect any records for key {} with token {}. " +
                    "This is possible when refresh interval fires for the final time " +
                    "after the lock has been released",
                    key, token);
       }

       return refreshed;
   }

使用  

private  LockService lockService;

private void tryAcquireLockAndSchedule() {
        while (!this.stopSchedule) {
            // 嘗試拿鎖
            this.token = this.lockService.acquire(SCHEDULER_LOCK, 20000);
            if (this.token != null) {
    // 拿到鎖
            } else {
                // 等待LOCK_EXPIRATION, 再次嘗試
                Thread.sleep(LOCK_EXPIRATION);
            }
        }
    }

  • 先嘗試拿鎖,如果獲取到token,說(shuō)明拿鎖成功
  • 否則可以sleep一段時(shí)間后再拿鎖

完整代碼,可到github查看 https://github.com/jadepeng/docker-pipeline/blob/main/pipeline-master/src/main/java/com/github/jadepeng/pipeline/service/impl/MongoLockService.java

到此這篇關(guān)于java基于mongodb實(shí)現(xiàn)分布式鎖的示例代碼的文章就介紹到這了,更多相關(guān)java mongodb實(shí)現(xiàn)分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA性能優(yōu)化設(shè)置(解決卡頓問(wèn)題)

    IDEA性能優(yōu)化設(shè)置(解決卡頓問(wèn)題)

    在我們?nèi)粘J褂肐DEA進(jìn)行開(kāi)發(fā)時(shí),可能會(huì)遇到許多卡頓的瞬間,本文主要介紹了IDEA性能優(yōu)化設(shè)置,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2023-05-05
  • springmvc圖片上傳及json數(shù)據(jù)轉(zhuǎn)換過(guò)程詳解

    springmvc圖片上傳及json數(shù)據(jù)轉(zhuǎn)換過(guò)程詳解

    這篇文章主要介紹了springmvc圖片上傳及json數(shù)據(jù)轉(zhuǎn)換過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java中的forEach循環(huán)詳細(xì)解讀

    Java中的forEach循環(huán)詳細(xì)解讀

    這篇文章主要介紹了Java中的forEach循環(huán)詳細(xì)解讀,不要再foreach循環(huán)里面進(jìn)行元素的add和remove,如果你非要進(jìn)行remove元素,那么請(qǐng)使用Iterator方式,如果存在并發(fā),那么你一定要選擇加鎖,需要的朋友可以參考下
    2023-12-12
  • 淺談JAVA并發(fā)之ReentrantLock

    淺談JAVA并發(fā)之ReentrantLock

    本文主要介紹了基于A(yíng)QS實(shí)現(xiàn)的ReentrantLock(重入鎖),感興趣的同學(xué),可以參考下。
    2021-06-06
  • 使用Maven配置Spring的方法步驟

    使用Maven配置Spring的方法步驟

    這篇文章主要介紹了使用Maven配置Spring的方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • 解決Spring?Boot應(yīng)用打包后文件訪(fǎng)問(wèn)問(wèn)題

    解決Spring?Boot應(yīng)用打包后文件訪(fǎng)問(wèn)問(wèn)題

    在Spring Boot項(xiàng)目的開(kāi)發(fā)過(guò)程中,一個(gè)常見(jiàn)的挑戰(zhàn)是如何有效地訪(fǎng)問(wèn)和操作資源文件,本文就來(lái)介紹一下解決Spring?Boot應(yīng)用打包后文件訪(fǎng)問(wèn)問(wèn)題,感興趣的可以了解一下
    2024-01-01
  • Java開(kāi)發(fā)之普通web項(xiàng)目轉(zhuǎn)為Maven項(xiàng)目的方法

    Java開(kāi)發(fā)之普通web項(xiàng)目轉(zhuǎn)為Maven項(xiàng)目的方法

    這篇文章主要給大家介紹了關(guān)于Java開(kāi)發(fā)之普通web項(xiàng)目轉(zhuǎn)為Maven項(xiàng)目的相關(guān)資料,文中通過(guò)圖文將轉(zhuǎn)換的方法步驟介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • JAVA 使用正則提取A標(biāo)簽以及href鏈接

    JAVA 使用正則提取A標(biāo)簽以及href鏈接

    這篇文章主要介紹了JAVA 使用正則提取A標(biāo)簽以及href鏈接的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java通過(guò)JFrame做一個(gè)登錄系統(tǒng)的界面完整代碼示例

    java通過(guò)JFrame做一個(gè)登錄系統(tǒng)的界面完整代碼示例

    這篇文章主要介紹了java通過(guò)JFrame做一個(gè)登錄系統(tǒng)的界面完整代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • IDEA運(yùn)行導(dǎo)入的javaweb項(xiàng)目tomcat正常,但是運(yùn)行失敗404問(wèn)題

    IDEA運(yùn)行導(dǎo)入的javaweb項(xiàng)目tomcat正常,但是運(yùn)行失敗404問(wèn)題

    這篇文章主要介紹了IDEA運(yùn)行導(dǎo)入的javaweb項(xiàng)目tomcat正常但是運(yùn)行失敗404問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評(píng)論