ToB企服应用市场:ToB评测及商务社交产业平台

标题: 锁 - 分布式锁工具 [打印本页]

作者: 民工心事    时间: 2022-12-3 17:38
标题: 锁 - 分布式锁工具
锁概述

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。
锁相关概念
分类
相关阅读:
自定义锁工具

1 :Redis 分布式锁(简单实现)

使用 ThreadLocal 保存锁对应的唯一标识
加锁:使用 STRING 保存锁定标识, 'SET key value PX NX' 确保一个 key 只能加锁一次
解锁:Lua 脚本判断是自己加的锁进行释放

2 :Redis 分布式锁

使用 ThreadLocal 保存 锁key 与 相应的唯一标识
加锁:使用 HASH 保存锁标识与加锁次数
解锁:Lua 脚本判断是自己加的锁进行释放
功能:可重入(Redis HASH)、支持对不同 key 进行加解锁(ThreadLocal)
<ul>工具类
     RedisLockUtil.java
  1. // 使用 ThreadLocal 保存 锁key 与 唯一标识
  2. private static final ThreadLocal<Map<String, String>> LOCK_FLAG =
  3.         ThreadLocal.withInitial(HashMap::new);
  4. // 尝试加锁
  5. private long tryLock(String key, long ttl) {
  6.     String uniqueFlag = LOCK_FLAG.get().get(key);
  7.     if (uniqueFlag == null) {
  8.         uniqueFlag = UUID.randomUUID().toString().replace("-", "");
  9.         LOCK_FLAG.get().put(key, uniqueFlag);
  10.     }
  11.     try {
  12.         List<String> keys = Collections.singletonList(key);
  13.         Object[] args = {uniqueFlag, ttl};
  14.         Long lockRes = redisTemplate.execute(LOCK_SCRIPT, keys, args);
  15.         log.debug("tryLock, lock_flag={}, key={}, args={}, lockRes={}",
  16.                 LOCK_FLAG.get(), key, args, lockRes);
  17.         return lockRes != null ? lockRes : 0L;
  18.     } catch (Exception e) {
  19.         log.error("tryLock occurred an exception", e);
  20.     }
  21.     return 0L;
  22. }
  23. // 尝试解锁
  24. public long tryUnlock(String key) {
  25.     String uniqueFlag = LOCK_FLAG.get().get(key);
  26.     if (uniqueFlag == null) {
  27.         return 0L;
  28.     }
  29.     long lockNum = -1L;
  30.     try {
  31.         List<String> keys = Collections.singletonList(key);
  32.         Object[] args = {uniqueFlag};
  33.         Long unlockRes = redisTemplate.execute(UNLOCK_SCRIPT, keys, args);
  34.         log.debug("unlock, key={}, args={}, unlockRes={}", key, args, unlockRes);
  35.         lockNum = unlockRes != null ? unlockRes : 0L;
  36.     } catch (Exception e) {
  37.         log.error("release lock occurred an exception", e);
  38.     } finally {
  39.         if (lockNum == 0L) {
  40.             LOCK_FLAG.get().remove(key);
  41.             if (LOCK_FLAG.get().isEmpty()) {
  42.                 LOCK_FLAG.remove();
  43.             }
  44.         }
  45.     }
  46.     return lockNum;
  47. }
复制代码
Lua 脚本
        加锁: redis_lock.lua
  1.   ```lua
  2.   local lock_key = KEYS[1];
  3.   local lock_flag = ARGV[1];
  4.   --- 锁定时长,单位:毫秒
  5.   local lock_ttl = tonumber(ARGV[2]);
  6.   --- HASH 支持可重入
  7.   --- lock_flag 保存加锁唯一标识
  8.   --- lock_num 保存加锁次数
  9.   local info = redis.call("HMGET", lock_key, "lock_flag", "lock_num");
  10.   local h_flag = info[1];
  11.   local h_num = tonumber(info[2]);
  12.   if (h_num == nil or h_num < 0) then
  13.       h_num = 0;
  14.   end
  15.   --- 返回加锁次数,未加锁成功返回 -1
  16.   if (not h_flag or h_flag == lock_flag) then
  17.       local res_num = h_num + 1;
  18.       redis.call("HMSET", lock_key, "lock_flag", lock_flag, "lock_num", res_num);
  19.       redis.call("PEXPIRE", lock_key, lock_ttl);
  20.       return res_num;
  21.   else
  22.       return -1;
  23.   end
  24.   ```
复制代码
         解锁: redis_lock.lua [code]  ```lua  local lock_key = KEYS[1];  local lock_flag = ARGV[1];  --- HASH 支持可重入  --- lock_flag 保存加锁唯一标识  --- lock_num 保存加锁次数  local info = redis.call("HMGET", lock_key, "lock_flag", "lock_num");  local h_flag = info[1];  local h_num = tonumber(info[2]);  if (h_num == nil) then      h_num = 0;  end  --- 返回剩余加锁次数,未被加锁或解锁完返回 0,非自己加锁返回 -1  if (not h_flag) then      return 0;  elseif (h_flag == lock_flag) then      if (h_num




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4