使用Redis和zookeeper实现分布式锁

Redis

Redis分布式锁:

加锁:

/**
 * 获取锁
 * @param lockKey 锁
 * @param identity 身份标识(保证锁不会被其他人释放)
 * @param expireTime 锁的过期时间(单位:秒)
 * @return
 */
public boolean lock(String lockKey, String identity, long expireTime){
   
  boolean lockResult = redisTemplate.opsForValue().setIfAbsent(lockKey, identity, expireTime, TimeUnit.SECONDS);
  return opsForValue;
}

加锁的方法只需要三个参数:lockKey、identity、expireTime。
第一个参数lockKey为key,一个资源对应一个唯一的key。
第二个参数identity为身份标识,作为此key对应的value存储,为了判断在释放锁时是不是和加锁的身份相同,防止别人释放锁。
第三个参数expireTime为过期时间,此参数保证程序加锁后崩溃导致不能主动释放锁的时候自动释放锁,防止出现死锁。

解锁:

/**
 * 释放锁
 * @param lockKey 锁
 * @param identity 身份标识(保证锁不会被其他人释放)
 * @return
 */
public boolean releaseLock(String lockKey, String identity){
   
  String luaScript =
    "if " +
    " redis.call('get', KEYS[1]) == ARGV[1] " +
    "then " +
    " return redis.call('del', KEYS[1]) " +
    "else " +
    " return 0 " +
    "end";
  DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
  redisScript.setResultType(Boolean.class);
  redisScript.setScriptText(luaScript);
  List<String> keys = new ArrayList<>();
  keys.add(lockKey);
  boolean result = redisTemplate.execute(redisScript, keys, identity);
  return result;
}

解锁的方法只需两个参数:lockKey、identity。
第一个参数lockKey为key,一个资源对应一个唯一的key。
第二个参数identity为身份标识,作为此key对应的value存储,为了判断在释放锁时是不是和加锁的身份相同,防止别人释放锁。
此处使用Lua脚本来判断身份,身份相同就删除,身份不同就不对数据做操作并返回失败。为什么要使用Lua脚本呢?这是为了要保证操作的原子性,redis在执行Lua脚本的时候是把脚本当作一个命令来执行的,我们都知道redis的命令是都是原子操作,这样就保证了操作的原子性。

Zookeeper

  1. 创建一个锁目录 /lock;
  2. 当一个客户端需要获取锁时,在 /lock 下创建临时的且有序的子节点;
  3. 客户端获取 /lock 下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是,则认为获得锁;否则监听自己的前一个子节点,获得子节点的变更通知后重复此步骤直至获得锁;
  4. 执行业务代码,完成后,删除对应的子节点。
全部评论

相关推荐

12-06 20:47
已编辑
复旦大学 C++
华为 终端小艺 定级估计是15a
khj:只要家里条件还行和不愿意太卷真别去华为这种农村做题家云集的地方
点赞 评论 收藏
分享
11-07 13:31
怀化学院 Java
勇敢牛牛不怕难:又疯一个
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务