Redis的分布式锁实现

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis的分布式锁实现

 分布式锁一般有三种实现方式:

1. 数据库乐观锁;

2. 基于Redis的分布式锁;

3. 基于ZooKeeper的分布式锁。

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问

分布式锁的使用场景: 线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!

分布式锁的实现(Redis)

几个要用到的redis命令:

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

get(key):获得key对应的value值,若不存在则返回nil。

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

expire(key, seconds):设置key-value的有效期为seconds秒。

代码实现:

依赖引入:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

image.gif

public class RedisPool { 
     private static JedisPool pool;//jedis连接池 
     private static int maxTotal = 20;//最大连接数 
     private static int maxIdle = 10;//最大空闲连接数 
     private static int minIdle = 5;//最小空闲连接数 
     private static boolean testOnBorrow = true;//在取连接时测试连接的可用性 
     private static boolean testOnReturn = false;//再还连接时不测试连接的可用性
     static {
         initPool();//初始化连接池
     }
     public static Jedis getJedis(){
         return pool.getResource();
     }
     public static void close(Jedis jedis){
         jedis.close();
     }
     private static void initPool(){
         JedisPoolConfig config = new JedisPoolConfig();
         config.setMaxTotal(maxTotal);
         config.setMaxIdle(maxIdle);
         config.setMinIdle(minIdle);
         config.setTestOnBorrow(testOnBorrow);
         config.setTestOnReturn(testOnReturn);
         config.setBlockWhenExhausted(true);
         pool = new JedisPool(config, “127.0.0.1”, 6379, 5000, “liqiyao”);
     }
 }

image.gif

Jedis的api进行封装:

public class RedisPoolUtil { 
     private RedisPoolUtil(){} 
     private static RedisPool redisPool; 
     public static String get(String key){
         Jedis jedis = null;
         String result = null;
         try {
             jedis = RedisPool.getJedis();
             result = jedis.get(key);
         } catch (Exception e){
             e.printStackTrace();
         } finally {
             if (jedis != null) {
                 jedis.close();
             }
             return result;
         }
     }
     public static Long setnx(String key, String value){ 
         Jedis jedis = null;
         Long result = null;
         try {
             jedis = RedisPool.getJedis();
             result = jedis.setnx(key, value);
         } catch (Exception e){
             e.printStackTrace();
         } finally {
             if (jedis != null) {
                 jedis.close();
             }
             return result;
         }
     }
     public static String getSet(String key, String value){
         Jedis jedis = null;
         String result = null;
         try {
             jedis = RedisPool.getJedis();
             result = jedis.getSet(key, value);
         } catch (Exception e){
             e.printStackTrace();
         } finally {
             if (jedis != null) {
                 jedis.close();
             }
             return result;
         }
     }
     public static Long expire(String key, int seconds){ 
         Jedis jedis = null;
         Long result = null;
         try {
             jedis = RedisPool.getJedis();
             result = jedis.expire(key, seconds);
         } catch (Exception e){
             e.printStackTrace();
         } finally {
             if (jedis != null) {
                 jedis.close();
             }
             return result;
         }
     }
     public static Long del(String key){ 
         Jedis jedis = null;
         Long result = null;
         try {
             jedis = RedisPool.getJedis();
             result = jedis.del(key);
         } catch (Exception e){
             e.printStackTrace();
         } finally {
             if (jedis != null) {
                 jedis.close();
             }
             return result;
         }
     }
 }

image.gif

分布式锁工具类:

public class DistributedLockUtil { 
     private DistributedLockUtil(){
     }
     public static boolean lock(String lockName){//lockName可以为共享变量名,也可以为方法名,主要是用于模拟锁信息
         System.out.println(Thread.currentThread() + “开始尝试加锁!”);
         Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));
         if (result != null && result.intValue() == 1){
             System.out.println(Thread.currentThread() + “加锁成功!”);
             RedisPoolUtil.expire(lockName, 5);
             System.out.println(Thread.currentThread() + “执行业务逻辑!”);
             RedisPoolUtil.del(lockName);
             return true;
         } else {
             String lockValueA = RedisPoolUtil.get(lockName);
             if (lockValueA != null && Long.parseLong(lockValueA) >= System.currentTimeMillis()){
                 String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));
                 if (lockValueB == null || lockValueB.equals(lockValueA)){
                     System.out.println(Thread.currentThread() + “加锁成功!”);
                     RedisPoolUtil.expire(lockName, 5);
                     System.out.println(Thread.currentThread() + “执行业务逻辑!”);
                     RedisPoolUtil.del(lockName);
                     return true;
                 } else {
                     return false;
                 }
             } else {
                 return false;
             }
         }
     }
 }

image.gif

加锁代码:

public class RedisTool {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}

image.gif

解锁代码:

public class RedisTool {
    private static final Long RELEASE_SUCCESS = 1L;
    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, 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 (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}

image.gif

基于redisson分布式锁

配置文件:

<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.11.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

image.gif

@Autowired
    private RedissonClient redissonClient;
    @RequestMapping("/redissonLock")
    public String redissonLock() throws InterruptedException { 
        RLock rLock = redissonClient.getLock("order");
        log.info("我进入了方法");
        rLock.lock(30, TimeUnit.SECONDS);
        log.info("获得了锁");
        Thread.sleep(15000);
        log.info("释放了锁");
        rLock.unlock();
        log.info("方法执行完成");
        return "方法执行完成";
    }

image.gif


文章下方有交流学习区!一起学习进步!也可以前往官网,加入官方微信交流群

创作不易,如果觉得文章不错,可以点赞收藏评论

你的支持和鼓励是我创作的动力❗❗❗

官网Doker 多克;官方旗舰店首页-Doker 多克-淘宝网  全品优惠

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
NoSQL Java 大数据
介绍redis分布式锁
分布式锁是解决多进程在分布式环境中争夺资源的问题,与本地锁相似但适用于不同进程。以Redis为例,通过`setIfAbsent`实现占锁,加锁同时设置过期时间避免死锁。然而,获取锁与设置过期时间非原子性可能导致并发问题,解决方案是使用`setIfAbsent`的超时参数。此外,释放锁前需验证归属,防止误删他人锁,可借助Lua脚本确保原子性。实际应用中还有锁续期、重试机制等复杂问题,现成解决方案如RedisLockRegistry和Redisson。
|
1月前
|
NoSQL Redis 微服务
分布式锁_redis实现
分布式锁_redis实现
|
1月前
|
NoSQL 关系型数据库 MySQL
Redis实现分布式锁
Redis实现分布式锁
20 0
|
8月前
|
NoSQL Java 关系型数据库
Redis-分布式锁
分布式锁的基本原理和实现方式对比 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路 在分布式情况下有多个JVM,所以就有多个锁监视器,所以就存在有多个线程拿到锁,他们就会产生不互斥的情况,这也是我们为什么要使用分布式锁的原因。而从图中我们也可以看到分布式锁的原理:让多个微服务共用一个锁监视器,这样就不会有多把锁同时存在的情况。 那么分布式锁他应该满足一些什么样的条件呢? 可见性:多个线程都能看到相同的结果,注意:这个地方说的
39 1
|
8月前
|
NoSQL 安全 关系型数据库
Redis实现分布式锁(1)
Redis实现分布式锁(1)
|
11月前
|
NoSQL 算法 Redis
Redis的分布式锁
Redis的分布式锁的基本实现和注意事项
56 0
|
NoSQL 安全 关系型数据库
Redis 实现分布式锁
分布式锁,主要考察使用者对原子性的理解,原子性可以保证程序从异常中恢复后,redis中的数据是正确的,程序依然正常运行。分布式锁是实现线程同步手段之一。
152 0
|
NoSQL PHP Redis
redis实现分布式锁
redis实现分布式锁
149 0
redis实现分布式锁
|
NoSQL 安全 Java
Redis 分布式锁
Redis 分布式锁
255 1
Redis 分布式锁
|
消息中间件 NoSQL Java
基于Redis实现分布式锁
基于Redis实现分布式锁
247 0
基于Redis实现分布式锁

热门文章

最新文章