Redis 分布式锁

Redis 实现分布式锁有多种方式,在实际业务场景可根据实际情况选择实现方式

简单的例子,基于 spring-data-redis

@Service
public class RedisLockService {

    @Autowired private RedisTemplate<String, Long> redisTemplate;

    public boolean lock(String key) {
        if (redisTemplate.opsForValue().setIfAbsent(key, Thread.currentThread().getId())) {
            redisTemplate.expire(key, 10, TimeUnit.SECONDS);
            return true;
        } else {
            return false;
        }

    }

    public boolean unlock(String key) {
        Long lock = redisTemplate.opsForValue().get(key);
        if (lock != null && Thread.currentThread().getId() == lock) {
            redisTemplate.delete(key);
            return true;
        } else {
            return false;
        }
    }
}

基于 Redis 的 setnx 方式,获取名为 key 的锁,将当前线程 id 作为值,用于解锁判断,设置超时时间以防锁一直没有被释放。
这里只是举个例子,上面的代码有很多东西没有考虑,比如加锁时,设值和设置超时时间不是原子性的,如果设完值后 Redis 挂了,没有设置到超时时间,就无法自动解锁。

那么如何使多条命令有原子性呢,Spring 给出了使用Lua脚本的例子 Spring-data-redis script

@Bean
public RedisScript<Boolean> script() {

  ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("META-INF/scripts/checkandset.lua");
  return RedisScript.of(scriptSource, Boolean.class);
}
public class Example {

  @Autowired
  RedisScript<Boolean> script;

  public boolean checkAndSet(String expectedValue, String newValue) {
    return redisTemplate.execute(script, singletonList("key"), asList(expectedValue, newValue));
  }
}
-- checkandset.lua
local current = redis.call('GET', KEYS[1])
if current == ARGV[1]
  then redis.call('SET', KEYS[1], ARGV[2])
  return true
end
return false

Redis 官方给出了分布式锁的算法,Redlock,实现方式较复杂,
有篇关于 Redlock 是否安全的 文章

Redis 官方推荐实现了 Redlock 的 Java 客户端是 Redisson

Redisson 提供了即开即用的分布式锁服务 Redisson 分布式锁

// 1. Create config object
Config = ...

// 2. Create Redisson instance
RedissonClient redisson = Redisson.create(config);

// 3. Get object you need
RMap<MyKey, MyValue> map = redisson.getMap("myMap");

RLock lock = redisson.getLock("myLock");

RExecutorService executor = redisson.getExecutorService("myExecutorService");

// over 30 different objects and services ...

你可能感兴趣的:(Java)