专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Redis实现分布式锁

参考网址:

https://tech.souyunku.com6844903543590092814
https://www.jianshu.com/p/533072fa4d52
https://tech.souyunku.com/zhili/p/redisdistributelock.html
https://tech.souyunku.com6844903830442737671#heading-5

1. 分布式锁常见条件

(1)互斥性。临界区任一时刻只能被一个客户端的一个线程所执行。
(2)可重入性。获得锁的线程可以重复获得锁。
(3)获取锁和释放锁必须是相同线程
(4)自动释放锁。获取锁线程崩溃没有主动释放锁,锁仍然可以被其它线程获取。

理解

  • 条件1、2、3要求锁能够记录获取锁的机器+线程
  • 条件2要求锁需要同一个线程加锁次数进行计数
  • 条件4要求锁有过期时间

2. 基于Redis实现分布式锁

2.1 基于Redis实现分布式锁设计(未支持可重入锁)

优缺点

优点:借助redis高性能的特点,实现高性能分布式锁。
缺点:

加锁逻辑

89_1.png

解锁逻辑

89_2.png

实现设计

(1)key和value设计
key = lock.{resource};
value = {machineId}_{threadId};

(2)加锁和设置超时时间动作

需要保证set动作、expire动作原子性,主要有两种做法:
i. set时同时使用ex和nx

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

ii. 使用lua脚本执行set和expire

(3)释放锁操作

需要保证get动作、del动作原子性,依靠lua脚本实现原子性。

3. Redisson实现分布式锁

(1)分布式锁实现(未实现可重入锁和重试机制)

public <V> V executeReadWriteLuaScript(String luaScript, RScript.ReturnType returnType, List<Object> keys,
                                      Object[] values) {
    RScript rScript = getScript();
    return rScript.eval(RScript.Mode.READ_WRITE, luaScript, returnType, keys, values);
}

public boolean lock(String resource, Object machineId, Object threadId, long expireTime) {
    String key = "lock." + resource;
    String value = machineId.toString() + "_" + threadId.toString();
    return lock(key, value, expireTime);
}

public boolean lock(String key, String value, long expireTime) {
    RBucket<String> bucket = getBucket(key);
    return bucket.trySet(value, expireTime, TimeUnit.SECONDS);
}

public void unlock(String resource, Object machineId, Object threadId) {
    String key = "lock." + resource;
    String value = machineId.toString() + "_" + threadId.toString();
    unlock(key, value);
}

public void unlock(String key, String value) {
    String luaScript = "local value = redis.call('GET', KEYS[1]); " +
            "if (value == ARGV[1]) then " +
            "    redis.call('DEL', KEYS[1]); " +
            "end ";
    executeReadWriteLuaScript(luaScript, RScript.ReturnType.VALUE,
            Lists.newArrayList(key),
            Lists.newArrayList(value).toArray());
}

(2)测试代码

@Test
public void testDistributedLock() {
    Long machineId1 = 123L;
    String resource = "resource";

    Runnable r = () -> {
        if (redisServiceWithRetry.lock(resource, machineId1, Thread.currentThread().getId(), 5)) {
            try {
                System.out.println(Thread.currentThread().getName() + " locked");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                redisServiceWithRetry.unlock(resource, machineId1, Thread.currentThread().getId());
                System.out.println(Thread.currentThread().getName() + " unlocked");
            }
        } else {
            System.out.println(Thread.currentThread().getName() + " fail to lock");
        }
    };

    Thread t1 = new Thread(r);
    Thread t2 = new Thread(r);

    t1.start();
    t2.start();

    try {
        t1.join();
        t2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

结果:

89_3.png

文章永久链接:https://tech.souyunku.com/36704

未经允许不得转载:搜云库技术团队 » Redis实现分布式锁

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们