Redis分布式锁

概述

为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁

为什么要使用分布式锁

  • 成员变量 A 存在 JVM1、JVM2、JVM3 三个 JVM 内存中
  • 成员变量 A 同时都会在 JVM 分配一块内存,三个请求发过来同时对这个变量操作,显然结果是不对的
  • 不是同时发过来,三个请求分别操作三个不同 JVM 内存区域的数据,变量 A 之间不存在共享,也不具有可见性,处理的结果也是不对的
    注:该成员变量 A 是一个有状态的对象

如果我们业务中确实存在这个场景的话,我们就需要一种方法解决这个问题,这就是分布式锁要解决的问题

分布式锁应该具备哪些条件

  • 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  • 高可用的获取锁与释放锁
  • 高性能的获取锁与释放锁
  • 具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
  • 具备锁失效机制,防止死锁
  • 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

如何实现分布式锁

java实现分布式锁的方式有很多种,如利用数据库的乐观锁实现分布式锁 ,也可以通过Zookeeper临时节点实现,本文着重介绍Redis的使用方式

Redis的分布式锁实现方式

分布式锁的注意事项 

  • 互斥性:在任意时刻,只有一个客户端能持有锁 
  • 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。 
  • 可重入性:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。 

实现分布式锁

获取锁

方式1(使用set命令实现)--推荐 

/**     
  * 使用redis的set命令实现获取分布式锁    
  * @param lockKey       可以就是锁     
  * @param requestId     请求ID,保证同一性     
  * @param expireTime    过期时间,避免死锁     
  * @return     
*/    
public static boolean getLock(String lockKey,String requestId,int expireTime) {            
    //NX:保证互斥性        
    String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);        
    if("OK".equals(result)) {
            return true;        
    }                
    return false;    
}

方式2(使用setnx命令实现)

public static boolean getLock(String lockKey,String requestId,int expireTime) { 
       Long result = jedis.setnx(lockKey, requestId);
       if(result == 1) {
            jedis.expire(lockKey, expireTime);
            return true;
       }
       return false;    
}

释放锁

方式1(del命令实现)

 /**     
   * 释放分布式锁     
   * @param lockKey     
   * @param requestId     
   */    
public static void releaseLock(String lockKey,String requestId) {
        if (requestId.equals(jedis.get(lockKey))) {
            jedis.del(lockKey);        
        }    
}

方式2(redis+lua脚本实现)--推荐 

public static boolean releaseLock(String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (result.equals(1L)) {
            return true;
        }
        return false;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值