Redis 分布式鎖及緩存注釋的使用方法
使用工具:Apache an
測壓命令: ab -n 100 -c 100 http://www.baidu.com -n代表模擬100個請求,-c代表模擬100個并發,相當于100個人同時訪問
ab -t 60 -c 100 http://www.baidu.com 60秒100個并發,不斷發送請求
并發處理:
1.加synchronized鎖單線程處理、缺點: 無法做到細粒度控制 只適合單點的情況 同時運行內存緩慢,效率低(出現等待情況)
2.redis分布式鎖:
可以支撐每秒10多萬的并發,支持分布式,可以更細粒的控制代碼(多臺機器上多個線程對一個數據進行操作的互斥)
SETNX key value
將key設置值為value,如果key不存在,這種情況下等同于SET命令,當key存在時,什么也不做
GETSET key value
自動將key對應到value并且返回原來key和對應的value. 如果key存在但是對應的value不是字符串,就返回錯誤
DEMO演示:
加鎖處理方法:
|
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
|
@Component@Slf4jpublic class RedisLock { @Autowired private StringRedisTemplate stringRedisTemplate; //加鎖 /* * @param key id * @param value 當前時間+超時時間 * * */ public boolean lock(String key,String value){ if (stringRedisTemplate.opsForValue().setIfAbsent(key,value)){ return true;//加鎖成功就返回true } //不加下面這個可能出現死鎖情況 //代碼value加了過期時間* @param value 當前時間+超時時間
//獲取上一個鎖的時間,并判斷是否小于當前時間,小于就下一步判斷,就返回true加鎖成功
String currentValue=stringRedisTemplate.opsForValue().get(key); //如果鎖過期 if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue)<System.currentTimeMillis()){ //存儲時間要小于當前時間 //出現死鎖的另一種情況,當多個線程進來后都沒有返回true,接著往下執行,執行代碼有先后,而if判斷里只有一個線程才能滿足條件
//oldValue=currentValue
//多個線程進來后只有其中一個線程能拿到鎖(即oldValue=currentValue),其他的返回false
String oldValue=stringRedisTemplate.opsForValue().getAndSet(key,value); if (!StringUtils.isEmpty(oldValue)&& oldValue.equals(currentValue)){//上一個時間不為空,并且等于當前時間 return true; } } return false;//失敗返回false } //解鎖 public void unlock(String key,String value){//執行刪除可能出現異常需要捕獲 try { String currentValue = stringRedisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {//如果不為空,就刪除鎖 stringRedisTemplate.opsForValue().getOperations().delete(key); } }catch (Exception e){ log.error("[redis分布式鎖] 解鎖",e); } }} |
|
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
|
//秒殺demopprivate static final int TIMEOUT=10*1000;//超時時間設置為10s@Autowriteprivate RedisLock redisLock;public void method(String id){//加鎖-死鎖出現:即在加鎖后運行程序出現意外報了異常,而此時還沒調用解鎖方法//那么在下一個線程調用加鎖方法是就不能set,直接返回fale,然后一直停留在加鎖失敗狀態 這就出現了死鎖
long time=System.currentTimeMillis()+TIMEOUT;//如果加鎖不成功就拋出異常 if(!redisLock.lock.get(id,String.valueof(time))){throw new WechatSellException(101,"哎喲喂,人也太多了,換個姿勢再試試");}//加鎖成功就實現業務代碼處理//1.查詢該商品庫存,為0表示活動結束//2.下單3.扣庫存//解鎖redisLock.unlock(id,String.valueof(time)));} |
浙公網安備 33010602011771號