Open Source, Open Future!
  menu
120 文章
ღゝ◡╹)ノ❤️

Redis---Jedis---分布式锁

加解锁思路

加锁

image.png

解锁

image.png

代码实现

   private static final Long SUCCESS = 1L;

    /**
     * 加锁逻辑
     *
     * @param lock       要加的锁
     * @param requestId  客户端标识(谁加的锁,谁才有权限去解这个锁)
     * @param expireTime 过期时间(锁的持有者没解锁就挂了,到期自动解锁,避免死锁)
     * @return 是否加锁成功
     */
    public boolean getLock(String lock, String requestId, int expireTime) {
        Jedis jedis = new Jedis();
        // 1. 锁未被占用(key不存在),那么就加锁,并对锁设置过期时间
        // 2. 锁被占用(key存在),不做任何操作
        String result = jedis.set(lock, requestId, "NX", "PX", expireTime);
        return "OK".equals(result);
    }

    /**
     * 解锁逻辑
     *
     * @param lock      要解的锁
     * @param requestId 客户端标识
     * @return 是否解锁成功
     */
    public boolean unlock(String lock, String requestId) {
        Jedis jedis = new Jedis();
        // Lua脚本(里面的所有操作具有原子性)
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        // lock --> KEYS[1] , requestId --> ARGV[1]
        // 1、获取lock的值value;2、value与requestId对比;3、若相等则删除lock,否则return 0
        Object result = jedis.eval(script, Arrays.asList(lock), Arrays.asList(requestId));
        return SUCCESS.equals(result);
    }

测试代码

    // 锁
    private static final String LOCK = "sss";

    // 客户端A标识(方便测试,这里简单随便写个值)
    private static String clientA = "clientA";

    // 客户端B标识
    private static String clientB = "clientB";

    // 过期时间
    private static int expireTime = 30000;

    @Test
    public void getLockByClientA() {
        printResult(clientA, getLock(LOCK, clientA, expireTime), 1);
    }

    @Test
    public void unlockByClientA() {
        printResult(clientA, unlock(LOCK, clientA), 2);
    }

    @Test
    public void getLockByClientB() {
        printResult(clientB, getLock(LOCK, clientB, expireTime), 1);
    }

    @Test
    public void unlockByClientB() {
        printResult(clientB, unlock(LOCK, clientB), 2);
    }

    public void printResult(String client, boolean result, int mode) {
        String op = (mode == 1 ? "获取锁" : "释放锁");
        String status = (result ? "成功" : "失败");
        System.out.println(client + op + status);
    }

    @Test
    public void checkLock() {
        Jedis jedis = new Jedis();
        String requestId = jedis.get(LOCK);
        Long time = jedis.pttl(LOCK);
        if (time.equals(-2L)) {
            System.out.println("锁" + LOCK + "未被占用,可获取");
        } else if (time.equals(-1L)) {
            System.out.println("锁" + LOCK + "已被" + requestId + "占用,没有设置过期时间");

        } else {
            System.out.println("锁" + LOCK + "已被" + requestId + "占用," + time + "毫秒后将过期");
        }
    }

    @Test
    public void testDemo() {
        checkLock();
        getLockByClientA();
        checkLock();
        getLockByClientB();
        unlockByClientB();
        checkLock();
        unlockByClientA();
        checkLock();
        getLockByClientB();
    }

测试结果

image.png