国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

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

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - 基于Redis分布式鎖的實現代碼

基于Redis分布式鎖的實現代碼

2019-11-13 14:10liuyang0 Redis

這篇文章主要介紹了Redis分布式鎖的實現,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

概述

目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們“任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多只能同時滿足兩項。”所以,很多系統在設計之初就要對這三者做出取舍。在互聯網領域的絕大多數的場景中,都需要犧牲強一致性來換取系統的高可用性,系統往往只需要保證“最終一致性”,只要這個最終時間是在用戶可以接受的范圍內即可。

在很多場景中,我們為了保證數據的最終一致性,需要很多的技術方案來支持,比如分布式事務、分布式鎖等。

選用Redis實現分布式鎖原因

Redis有很高的性能

Redis命令對此支持較好,實現起來比較方便

在此就不介紹Redis的安裝了。

使用命令介紹

SETNX

SETNX key val
當且僅當key不存在時,set一個key為val的字符串,返回1;若key存在,則什么都不做,返回0。

expire

expire key timeout
為key設置一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。

delete

delete key
刪除key

在使用Redis實現分布式鎖的時候,主要就會使用到這三個命令。

實現

使用的是jedis來連接Redis。

實現思想

獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。
分布式鎖的核心代碼如下:

?
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
98
99
100
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisException;
import java.util.List;
import java.util.UUID;
/**
 * Created by liuyang on 2017/4/20.
 */
public class DistributedLock {
 private final JedisPool jedisPool;
 public DistributedLock(JedisPool jedisPool) {
 this.jedisPool = jedisPool;
 }
 /**
 * 加鎖
 * @param locaName 鎖的key
 * @param acquireTimeout 獲取超時時間
 * @param timeout 鎖的超時時間
 * @return 鎖標識
 */
 public String lockWithTimeout(String locaName,
     long acquireTimeout, long timeout) {
 Jedis conn = null;
 String retIdentifier = null;
 try {
  // 獲取連接
  conn = jedisPool.getResource();
  // 隨機生成一個value
  String identifier = UUID.randomUUID().toString();
  // 鎖名,即key值
  String lockKey = "lock:" + locaName;
  // 超時時間,上鎖后超過此時間則自動釋放鎖
  int lockExpire = (int)(timeout / 1000);
  // 獲取鎖的超時時間,超過這個時間則放棄獲取鎖
  long end = System.currentTimeMillis() + acquireTimeout;
  while (System.currentTimeMillis() < end) {
  if (conn.setnx(lockKey, identifier) == 1) {
   conn.expire(lockKey, lockExpire);
   // 返回value值,用于釋放鎖時間確認
   retIdentifier = identifier;
   return retIdentifier;
  }
  // 返回-1代表key沒有設置超時時間,為key設置一個超時時間
  if (conn.ttl(lockKey) == -1) {
   conn.expire(lockKey, lockExpire);
  }
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
   Thread.currentThread().interrupt();
  }
  }
 } catch (JedisException e) {
  e.printStackTrace();
 } finally {
  if (conn != null) {
  conn.close();
  }
 }
 return retIdentifier;
 }
 /**
 * 釋放鎖
 * @param lockName 鎖的key
 * @param identifier 釋放鎖的標識
 * @return
 */
 public boolean releaseLock(String lockName, String identifier) {
 Jedis conn = null;
 String lockKey = "lock:" + lockName;
 boolean retFlag = false;
 try {
  conn = jedisPool.getResource();
  while (true) {
  // 監視lock,準備開始事務
  conn.watch(lockKey);
  // 通過前面返回的value值判斷是不是該鎖,若是該鎖,則刪除,釋放鎖
  if (identifier.equals(conn.get(lockKey))) {
   Transaction transaction = conn.multi();
   transaction.del(lockKey);
   List<Object> results = transaction.exec();
   if (results == null) {
   continue;
   }
   retFlag = true;
  }
  conn.unwatch();
  break;
  }
 } catch (JedisException e) {
  e.printStackTrace();
 } finally {
  if (conn != null) {
  conn.close();
  }
 }
 return retFlag;
 }
}

測試

下面就用一個簡單的例子測試剛才實現的分布式鎖。
例子中使用50個線程模擬秒殺一個商品,使用--運算符來實現商品減少,從結果有序性就可以看出是否為加鎖狀態。

模擬秒殺服務,在其中配置了jedis線程池,在初始化的時候傳給分布式鎖,供其使用。

?
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
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
 
/**
 * Created by liuyang on 2017/4/20.
 */
public class Service {
 private static JedisPool pool = null;
 static {
 JedisPoolConfig config = new JedisPoolConfig();
 // 設置最大連接數
 config.setMaxTotal(200);
 // 設置最大空閑數
 config.setMaxIdle(8);
 // 設置最大等待時間
 config.setMaxWaitMillis(1000 * 100);
 // 在borrow一個jedis實例時,是否需要驗證,若為true,則所有jedis實例均是可用的
 config.setTestOnBorrow(true);
 pool = new JedisPool(config, "127.0.0.1", 6379, 3000);
 }
 DistributedLock lock = new DistributedLock(pool);
 int n = 500;
 public void seckill() {
 // 返回鎖的value值,供釋放鎖時候進行判斷
 String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
 System.out.println(Thread.currentThread().getName() + "獲得了鎖");
 System.out.println(--n);
 lock.releaseLock("resource", indentifier);
 }
}
// 模擬線程進行秒殺服務
 
public class ThreadA extends Thread {
 private Service service;
 public ThreadA(Service service) {
 this.service = service;
 }
 @Override
 public void run() {
 service.seckill();
 }
}
 
public class Test {
 public static void main(String[] args) {
 Service service = new Service();
 for (int i = 0; i < 50; i++) {
  ThreadA threadA = new ThreadA(service);
  threadA.start();
 }
 }
}

結果如下,結果為有序的。

基于Redis分布式鎖的實現代碼

若注釋掉使用鎖的部分

?
1
2
3
4
5
6
7
public void seckill() {
 // 返回鎖的value值,供釋放鎖時候進行判斷
 //String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
 System.out.println(Thread.currentThread().getName() + "獲得了鎖");
 System.out.println(--n);
 //lock.releaseLock("resource", indentifier);
}

從結果可以看出,有一些是異步進行的。

基于Redis分布式鎖的實現代碼

在分布式環境中,對資源進行上鎖有時候是很重要的,比如搶購某一資源,這時候使用分布式鎖就可以很好地控制資源。
當然,在具體使用中,還需要考慮很多因素,比如超時時間的選取,獲取鎖時間的選取對并發量都有很大的影響,上述實現的分布式鎖也只是一種簡單的實現,主要是一種思想。

下一次我會使用zookeeper實現分布式鎖,使用zookeeper的可靠性是要大于使用redis實現的分布式鎖的,但是相比而言,redis的性能更好。

上面的代碼可以在我的GitHub中進行查看。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
主站蜘蛛池模板: 久国产精品韩国三级视频 | 精品成人在线视频 | 一级色网站| 欧美日韩中文在线观看 | 欧美中文一区二区三区 | 久久不卡 | 精品一区二区三 | 国产视频一区二区三区在线观看 | 日本一区免费 | 狠狠干天天草 | 一级久久久 | 偷拍呻吟高潮91 | 国产在线观看一区二区 | 久久久国产精品 | 精品粉嫩超白一线天av | 动漫一区二区三区 | 久久性网站 | 日日干夜夜操 | 亚洲色图88 | 91久久国产综合久久 | 五月婷婷丁香在线 | 国产玖玖| 日韩av电影在线观看 | 日韩在线观看一区 | 色噜噜狠狠狠综合曰曰曰 | 日韩视频在线免费观看 | 一区视频 | 精品在线 | 91精品国产日韩91久久久久久 | 日韩欧美精品在线 | 国产一区二区免费 | 国产91精品一区二区绿帽 | 亚洲五码中文字幕 | 亚洲高清一区二区三区 | 自拍在线 | 欧美一级免费 | 日韩免费精品 | 久久精品成人 | 蜜桃国精产品二三三区视频 | 日韩视频在线观看一区 | 欧美色影院 |