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

mongo分布式鎖Java實現方法(推薦)

 更新時間:2017年07月07日 10:51:42   投稿:jingxian  
下面小編就為大家?guī)硪黄猰ongo分布式鎖Java實現方法(推薦)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、分布式鎖使用場景:

代碼部署在多臺服務器上,即分布式部署。

多個進程同步訪問一個共享資源。

二、需要的技術:

數據庫:mongo

java:mongo操作插件類 MongoTemplate(maven引用),如下:

<!--mongodo開始-->
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-mongodb</artifactId>
      <version>1.8.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-commons</artifactId>
      <version>1.10.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongo-java-driver</artifactId>
      <version>2.13.0-rc2</version>
    </dependency>
 <!--mongodo結束-->

三、實現代碼:

主實現邏輯及外部調用方法,獲得鎖調用getLock,釋放鎖調用releaseLock,詳情如下:

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class MongoDistributedLock {

  static MongoLockDao mongoLockDao;

  static {
    mongoLockDao = SpringBeanUtils.getBean("mongoLockDao");
  }

  /**
   * 獲得鎖的步驟:
   * 1、首先判斷鎖是否被其他請求獲得;如果沒被其他請求獲得則往下進行;
   * 2、判斷鎖資源是否過期,如果過期則釋放鎖資源;
   * 3.1、嘗試獲得鎖資源,如果value=1,那么獲得鎖資源正常;(在當前請求已經獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。)
   * 3.2、value>1,則表示當前請求在嘗試獲取鎖資源過程中,其他請求已經獲取了鎖資源,即當前請求沒有獲得鎖;
   * !??!注意,不需要鎖資源時,及時釋放鎖資源?。?!。
   *
   * @param key
   * @param expire
   * @return
   */
  public static boolean getLock(String key, long expire) {
    List<MongoLock> mongoLocks = mongoLockDao.getByKey(key);
    //判斷該鎖是否被獲得,鎖已經被其他請求獲得,直接返回
    if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() >= System.currentTimeMillis()) {
      return false;
    }
    //釋放過期的鎖
    if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() < System.currentTimeMillis()) {
      releaseLockExpire(key, System.currentTimeMillis());
    }
    //??!(在高并發(fā)前提下)在當前請求已經獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。
    Map<String, Object> mapResult = mongoLockDao.incrByWithExpire(key, 1, System.currentTimeMillis() + expire);
    //如果結果是1,代表當前請求獲得鎖
    if ((Integer) mapResult.get("value") == 1) {
      return true;
      //如果結果>1,表示當前請求在獲取鎖的過程中,鎖已被其他請求獲得。
    } else if ((Integer) mapResult.get("value") > 1) {
      return false;
    }
    return false;
  }

  /**
   * 釋放鎖
   *
   * @param key
   */
  public static void releaseLock(String key) {
    Map<String, Object> condition = new HashMap<>();
    condition.put("key", key);
    mongoLockDao.remove(condition);
  }

  /**
   * 釋放過期鎖
   *
   * @param key
   * @param expireTime
   */
  private static void releaseLockExpire(String key, long expireTime) {
    mongoLockDao.removeExpire(key, expireTime);
  }
}

MongoLockDao實現代碼:

import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Repository
public class MongoLockDao <MongoLock> {
  private Class<?> clz;

  public Class<?> getClz() {
    if (clz == null) {
      //獲取泛型的Class對象
      clz = ((Class<?>)
          (((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]));
    }
    return clz;
  }

  /**
   * 返回指定key的數據
   *
   * @param key
   * @return
   */
  public List<MongoLock> getByKey(String key) {
    Query query = new Query();
    query.addCriteria(Criteria.where("key").is(key));
    return (List<MongoLock>) mongoTemplate.find(query, getClz());
  }


  /**
   * 指定key自增increment(原子加),并設置過期時間
   *
   * @param key
   * @param increment
   * @param expire
   * @return
   */
  public Map<String, Object> incrByWithExpire(String key, double increment, long expire) {
    //篩選
    Query query = new Query();
    query.addCriteria(new Criteria("key").is(key));

    //更新
    Update update = new Update();
    update.inc("value", increment);
    update.set("expire", expire);
    //可選項
    FindAndModifyOptions options = FindAndModifyOptions.options();
    //沒有則新增
    options.upsert(true);
    //返回更新后的值
    options.returnNew(true);
    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put("value", Double.valueOf(((MongoLock)
        mongoTemplate.findAndModify(query, update, options, getClz())).getValue()).intValue());
    resultMap.put("expire", Long.valueOf(((MongoLock)
        mongoTemplate.findAndModify(query, update, options, getClz())).getExpire()).longValue());
    return resultMap;
  }


  /**
   * 根據value刪除過期的內容
   *
   * @param key
   * @param expireTime
   */
  public void removeExpire(String key, long expireTime) {
    Query query = new Query();
    query.addCriteria(Criteria.where("key").is(key));
    query.addCriteria(Criteria.where("expire").lt(expireTime));
    mongoTemplate.remove(query, getClz());
  }

  public void remove(Map<String, Object> condition) {
    Query query = new Query();
    Set<Map.Entry<String, Object>> set = condition.entrySet();
    int flag = 0;
    for (Map.Entry<String, Object> entry : set) {
      query.addCriteria(Criteria.where(entry.getKey()).is(entry.getValue()));
      flag = flag + 1;
    }
    if (flag == 0) {
      query = null;
    }
    mongoTemplate.remove(query, getClz());
  }

}

MongoLock實體:

public class MongoLock {

  private String key;
  private double value;
  private long expire;

  public double getValue() {
    return value;
  }

  public void setValue(double value) {
    this.value = value;
  }

  public long getExpire() {
    return expire;
  }

  public void setExpire(long expire) {
    this.expire = expire;
  }

  public String getKey() {
    return key;
  }

  public void setKey(String key) {
    this.key = key;
  }
}

四、設計思路

前提:利用mongo實現id自增,且自增過程為原子操作,即線程安全。

假設有A、B兩個請求通過請求資源。

當A請求到資源是調用mongo自增 +1,并將結果返回給A,即1,此時結果等于1則表明,A請求過程中沒有其他請求請求到資源,將鎖資源分配給A。

當B請求到資源是調用mongo自增 +1,并將結果返回給A,即2。此時結果大于1則表明,B請求過程中有其他請求請求到資源,鎖資源不能分配給B。

這樣就是實現了多個請求請求同一個鎖并且排隊。

關于鎖過期時間 :

如果圖中代碼1releaseLockExpire(key, System.currentTimeMillis())修改為releaseLockExpire(key),即在釋放鎖的時候沒有傳入過期時間,會產生如下情況:

A、B兩個請求同時通過條件,進入到代碼 1

B執(zhí)行完刪除操作,進入代碼2,并且剛剛獲得到鎖資源,而此時A及有可能剛開始執(zhí)行釋放鎖的操作。

此時就會發(fā)生,A釋放了B剛剛獲得的鎖,這樣B就會失去剛剛獲得的鎖,而B確沒有感知,從而造成邏輯錯誤。

而releaseLockExpire(key, System.currentTimeMillis()),即在釋放鎖的時候判斷一下過期時間,這樣就不會誤刪B剛剛獲得的鎖。

以上這篇mongo分布式鎖Java實現方法(推薦)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java IO流對文件File操作

    Java IO流對文件File操作

    這篇文章主要介紹了Java IO流對文件File操作,java封裝的一個操作文件及文件夾(目錄)的對象??梢圆僮鞔疟P上的任何一個文件和文件夾
    2022-12-12
  • Java?JWT實現跨域身份驗證方法詳解

    Java?JWT實現跨域身份驗證方法詳解

    JWT(JSON?Web?Token)是目前流行的跨域認證解決方案,是一個開放標準(RFC?7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。本文將介紹JWT如何實現跨域身份驗證,感興趣的可以學習一下
    2022-01-01
  • Spring?Boot項目Jar包加密實戰(zhàn)教程

    Spring?Boot項目Jar包加密實戰(zhàn)教程

    本文詳細介紹了如何在Spring?Boot項目中實現Jar包加密,我們首先了解了Jar包加密的基本概念和作用,然后學習了如何使用Spring?Boot的Jar工具和第三方庫來實現Jar包的加密和解密,感興趣的朋友一起看看吧
    2024-02-02
  • 在@Value注解內使用SPEL自定義函數方式

    在@Value注解內使用SPEL自定義函數方式

    這篇文章主要介紹了在@Value注解內使用SPEL自定義函數方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • JAVA基于Slack實現異常日志報警詳解

    JAVA基于Slack實現異常日志報警詳解

    這篇文章主要為大家介紹了JAVA基于Slack實現異常日志報警詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • JSONObject?toJSONString錯誤的解決

    JSONObject?toJSONString錯誤的解決

    這篇文章主要介紹了JSONObject?toJSONString錯誤的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java如何根據根據IP地址獲取省市

    Java如何根據根據IP地址獲取省市

    這篇文章主要為大家詳細介紹了兩種在Java中獲取IP地址對應地理位置信息的方法,分別是使用ip2region庫和GeoIP庫,感興趣的小伙伴可以了解下
    2025-01-01
  • SpringBoot中swagger的使用

    SpringBoot中swagger的使用

    這篇文章主要介紹了SpringBoot中swagger的使用,文中有非常詳細的代碼示例,對正在學習swagger的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • Kotlin 泛型詳解及簡單實例

    Kotlin 泛型詳解及簡單實例

    這篇文章主要介紹了 Kotlin 泛型詳解及簡單實例的相關資料,需要的朋友可以參考下
    2017-06-06
  • java程序員必會的遠程debug教程

    java程序員必會的遠程debug教程

    這篇文章主要為大家介紹了java程序員必會的遠程debug教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08

最新評論

丰顺县| 右玉县| 德安县| 临沧市| 徐水县| 宜阳县| 南昌县| 仙游县| 芦溪县| 德安县| 江阴市| 长泰县| 巴东县| 海盐县| 呼伦贝尔市| 潜江市| 灵璧县| 辰溪县| 文安县| 达孜县| 泰安市| 东丰县| 黔西县| 黄石市| 柳林县| 邻水| 肥城市| 山东| 南木林县| 道真| 濮阳县| 北京市| 合江县| 许昌县| 循化| 甘洛县| 甘南县| 桐梓县| 张家川| 化州市| 彰化县|