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

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

服務(wù)器之家 - 編程語言 - Java教程 - mongo分布式鎖Java實現(xiàn)方法(推薦)

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

2020-11-28 14:59Java教程網(wǎng) Java教程

下面小編就為大家?guī)硪黄猰ongo分布式鎖Java實現(xiàn)方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、分布式鎖使用場景:

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

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

二、需要的技術(shù):

數(shù)據(jù)庫:mongo

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--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結(jié)束-->

三、實現(xiàn)代碼:

主實現(xiàn)邏輯及外部調(diào)用方法,獲得鎖調(diào)用getLock,釋放鎖調(diào)用releaseLock,詳情如下:

?
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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,那么獲得鎖資源正常;(在當前請求已經(jīng)獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導(dǎo)致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。)
   * 3.2、value>1,則表示當前請求在嘗試獲取鎖資源過程中,其他請求已經(jīng)獲取了鎖資源,即當前請求沒有獲得鎖;
   * !!!注意,不需要鎖資源時,及時釋放鎖資源!!!。
   *
   * @param key
   * @param expire
   * @return
   */
  public static boolean getLock(String key, long expire) {
    List<MongoLock> mongoLocks = mongoLockDao.getByKey(key);
    //判斷該鎖是否被獲得,鎖已經(jīng)被其他請求獲得,直接返回
    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ā)前提下)在當前請求已經(jīng)獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導(dǎo)致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。
    Map<String, Object> mapResult = mongoLockDao.incrByWithExpire(key, 1, System.currentTimeMillis() + expire);
    //如果結(jié)果是1,代表當前請求獲得鎖
    if ((Integer) mapResult.get("value") == 1) {
      return true;
      //如果結(jié)果>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實現(xiàn)代碼:

?
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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的數(shù)據(jù)
   *
   * @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(原子加),并設(shè)置過期時間
   *
   * @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;
  }
 
 
  /**
   * 根據(jù)value刪除過期的內(nèi)容
   *
   * @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實體:

?
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
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;
  }
}

四、設(shè)計思路

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

假設(shè)有A、B兩個請求通過請求資源。

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

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

這樣就是實現(xiàn)了多個請求請求同一個鎖并且排隊。

關(guān)于鎖過期時間 :

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

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

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

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

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

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

以上這篇mongo分布式鎖Java實現(xiàn)方法(推薦)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美色图亚洲 | poverty中国老妇人 | 午夜亚洲一区二区福利 | zoomkool最新版| 免费黄色片网站 | 5x社区在线观看直接进入 | 人人澡人| 校服下的白嫩小乳尖h1v1 | 97色资源| 97国产蝌蚪视频在线观看 | 国偷盗摄自产福利一区在线 | 久久精品视在线观看85 | 狠狠香蕉 | 亚洲免费一 | 丝瓜污污视频 | 俺去俺来也www色官网免费的 | 欧美一区二区三区久久久 | 亚洲a区视频 | 国产欧美一区二区三区免费 | 逼逼流水了 | pron在线观看 | 日本人在线看片 | 99热这里只有精品在线 | 国产欧美一区二区三区久久 | 高清一区二区 | 国内精品久久久久久久久久久久 | 国产亚洲精品第一综合另类 | 欧美贵妇vs高跟办公室 | 免费老外的毛片清高 | 美女和男生搞基 | www.爱情岛论坛 | 男女性gif抽搐出入视频 | 国产乱码在线精品可播放 | 免费在线观看成年人视频 | 夫妻性生活一级黄色片 | 波多野结衣一区 | 深夜免费看 | 2021国产麻豆剧传媒新片 | 91久久偷偷做嫩草影院免费 | 性福演算法 | 明星ai智能人脸替换造梦在线播放 |