一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - java基于mongodb實現(xiàn)分布式鎖的示例代碼

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

2021-11-02 13:29jqpeng的技術記事本 Java教程

本文主要介紹了java基于mongodb實現(xiàn)分布式鎖,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

原理

通過線程安全findAndModify 實現(xiàn)鎖

實現(xiàn)

定義鎖存儲對象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * mongodb 分布式鎖
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "distributed-lock-doc")
public class LockDocument {
    @Id
    private String id;
    private long expireAt;
    private String token;
}

定義Lock API:

?
1
2
3
4
5
6
7
8
public interface LockService {
 
    String acquire(String key, long expiration);
 
    boolean release(String key, String token);
 
    boolean refresh(String key, String token, long expiration);
}

獲取鎖:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@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);
 
      // 如果已過期
      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鎖對象,如果成功且token一致,說明拿到鎖
  • 否則加鎖失敗
  • 如果未拿到鎖,但是鎖已過期,嘗試刪除鎖
    • 如果刪除成功,再次嘗試拿鎖
    • 如果失敗,說明鎖可能已經(jīng)續(xù)期了

釋放和續(xù)期鎖:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@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;
}

使用  

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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,說明拿鎖成功
  • 否則可以sleep一段時間后再拿鎖

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

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

原文鏈接:https://www.cnblogs.com/xiaoqi/p/mongodb-lock.html

延伸 · 閱讀

精彩推薦
  • Java教程Java實現(xiàn)搶紅包功能

    Java實現(xiàn)搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 国产suv精品一区二区四区三区 | 红楼梦黄色小说 | www.羞羞答答 | 女人被爽到呻吟娇喘的视频动态图 | 楚乔传第二部免费观看全集完整版 | 九九久久国产精品免费热6 九九精品视频一区二区三区 | 国产一区在线播放 | 国产一及毛片 | 我和寂寞孕妇的性事 | 成年女人毛片免费观看97 | 成人福利网站含羞草 | 午夜桃色剧场 | 538精品视频 | 好男人天堂网 | 色在线看 | 色多多在线观看视频 | 无码国产成人777爽死 | 国产欧美久久久精品影院 | 亚洲成av人片天堂网 | 欧美日韩va| 国产精品国产三级国产专区不 | 91精品大神国产在线播放 | 美女污视频在线观看 | 精品久久久久久久国产潘金莲 | 午夜在线观看视频 | 男人边吃奶边做好爽视频免费 | 范冰冰好紧好滑好湿 | 免看一级一片一在线看 | 免费标准高清看机机桶机机 | 成人先锋 | 色婷亚洲| 欧美精品成人a多人在线观看 | 久久精品一区二区免费看 | 涩涩成人| 欧美精品一线二线大片 | 无套日出白浆在线播放 | 国产精品福利短视在线播放频 | 精品人人视屏 | 亚洲精品乱码蜜桃久久久 | 日本在线观看免费高清 | 国产精品亚洲一区二区久久 |