激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

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

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

2020-11-28 14:59Java教程網 Java教程

下面小編就為大家帶來一篇mongo分布式鎖Java實現方法(推薦)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、分布式鎖使用場景:

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

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

二、需要的技術:

數據庫: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結束-->

三、實現代碼:

主實現邏輯及外部調用方法,獲得鎖調用getLock,釋放鎖調用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,那么獲得鎖資源正常;(在當前請求已經獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。)
   * 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());
    }
    //!!(在高并發前提下)在當前請求已經獲得鎖的前提下,還可能有其他請求嘗試去獲得鎖,此時會導致當前鎖的過期時間被延長,由于延長時間在毫秒級,可以忽略。
    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實現代碼:

?
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的數據
   *
   * @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實體:

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

四、設計思路

前提:利用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執行完刪除操作,進入代碼2,并且剛剛獲得到鎖資源,而此時A及有可能剛開始執行釋放鎖的操作。

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

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

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久久久一区 | 黄网站免费观看视频 | 一级黄色片武则天 | 久草在线视频免费播放 | 黄污污网站 | 一本色道久久综合狠狠躁篇适合什么人看 | 成人免费福利视频 | 亚洲电影在线观看高清免费 | 久久久久北条麻妃免费看 | 欧美粗暴analvideos | 福利免费观看 | 国产亚洲综合一区二区 | 日本成年网 | 视频一区二区三区在线播放 | 色678黄网站全部免费 | 亚洲va久久久噜噜噜久牛牛影视 | 久久色网站 | 国产1区2区在线 | 国产一区二区三区四区在线 | 538任你躁在线精品视频网站 | 色中色在线视频 | 久久精品久久精品久久精品 | 日韩视频在线观看免费视频 | 国产精品久久久久久久久久 | 久久久久久久久久网 | 国产小视频在线 | 成人免费一区二区三区视频网站 | 国产91大片 | 国产高潮国产高潮久久久91 | 手机黄网www8xcn| 久久久久久久一区二区三区 | 久久久久免费电影 | 欧美日本免费一区二区三区 | 成人不卡在线观看 | 一级黄色毛片播放 | 精品一区在线视频 | 日韩视频观看 | 久色精品视频 | 欧美一级特黄aaaaaaa什 | 鲁丝一区二区三区不属 | 成人免费毛片片v |