分布式锁实现--Redis(Java)

分布式锁,是指在分布式的部署环境下,通过锁机制来让多客户端互斥的对共享资源进行访问。

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

  1. 基于关系型数据库,如MySQL
  2. 基于缓存数据库,如Redis
  3. 基于Zookeeper

此处对Redis如何实现分布式锁进行一下讲解

一、 实现原理

主要利用Redis的几个特点:

  1. "SET key value [EX seconds] [PX milliseconds] [NX|XX] "命令 如:SET key value EX 10 NX 若key不存在设置一个10秒过期的key-value
  2. "DEL" 命令 释放锁即删除对应key
  3. Redis是单线程的, 保证多个锁的竞争者只有一个能够创建key成功即获取到锁

SET key value [EX seconds] [PX milliseconds] [NX|XX] 命令:

EX seconds将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value
PX milliseconds将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value
NX 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。
XX 只在键已经存在时, 才对键进行设置操作。

二、可能存在的问题

1.锁的释放

A获取锁之后, 执行时间为15s, 锁的过期时间为10s, 当A执行完之前, B获取到了锁, A执行完之后使用DEL强制删key, 删除掉的其实是B获取到的锁

解决方案: 们可以在设置key的时候将value设置为一个唯一值uniqueValue(可以是随机值、UUID、或者机器号+线程号的组合、签名等)。当解锁时,也就是删除key的时候先判断一下key对应的value是否等于先前设置的值,如果相等才能删除key

但我们要保证 判断value是否相等的操作 与 删除 操作 的原子性

// GET  与  DEL 是两个分开的操作
if uniqueKey == GET(key) {
	DEL key
}

Lua脚本的原子性,在Redis执行该脚本的过程中,其他客户端的命令都需要等待该Lua脚本执行完才能执行

//其中ARGV[1]表示设置key时指定的唯一值。
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

2.Redis的master节点宕机

  1. 线程A在master节点拿到了锁。
  2. master节点在把A创建的key写入slave之前宕机了。
  3. slave变成了master节点。
  4. 线程B也得到了和A还持有的相同的锁。(因为原来的slave里面还没有A持有锁的信息)

三、代码示例

public boolean lock(String lockKey, String uniqueValue, int seconds){
    SetParams params = new SetParams();
    params.nx().ex(seconds);
    String result = jedis.set(lockKey, uniqueValue, params);
    if ("OK".equals(result)) {
        return true;
    }
    return false;
}

public boolean unlock(String lockKey, String uniqueValue){
    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(uniqueValue));
    if (result.equals(1)) {
        return true;
    }
    return false;
}

转自:

https://blog.csdn.net/u013256816/article/details/93305532

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redisson是基于Redis实现Java驻留内存数据网格的开源框架,提供了丰富的分布式锁实现方式。下面介绍基于Redisson的最优实现。 1. 初始化Redisson客户端 ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 2. 获取分布式锁 ```java RLock lock = redisson.getLock("myLock"); lock.lock(); try { // 业务逻辑 } finally { lock.unlock(); } ``` 3. 设置加锁超时时间和释放锁时限制 ```java RLock lock = redisson.getLock("myLock"); boolean locked = lock.tryLock(10, 60, TimeUnit.SECONDS); try { if (locked) { // 业务逻辑 } else { // 获取锁失败 } } finally { if (locked) { lock.unlock(); } } ``` 4. 实现可重入锁 ```java RLock lock = redisson.getLock("myLock"); lock.lock(); try { lock.lock(); try { // 业务逻辑 } finally { lock.unlock(); } } finally { lock.unlock(); } ``` 5. 实现公平锁 ```java RLock lock = redisson.getFairLock("myFairLock"); lock.lock(); try { // 业务逻辑 } finally { lock.unlock(); } ``` 6. 实现读写锁 ```java RReadWriteLock rwlock = redisson.getReadWriteLock("myReadWriteLock"); rwlock.readLock().lock(); try { // 读操作业务逻辑 } finally { rwlock.readLock().unlock(); } rwlock.writeLock().lock(); try { // 写操作业务逻辑 } finally { rwlock.writeLock().unlock(); } ``` 以上就是基于Redisson实现Redis分布式锁的最优实现Redisson提供了丰富的分布式锁实现,可以根据业务需求选择合适的锁类型。同时,Redisson还提供了许多其他功能,如分布式对象、分布式限流等,可以方便地实现分布式应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值