redis分布式锁实现

分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

1 互斥性,在任意时刻,只有一个客户端能持有锁。

2 不会发生死锁,即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

3 具有容错性,只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。

4 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

配置文件:

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=0

java代码实现:

package com.example.demo.redis;

import redis.clients.jedis.Jedis;

import java.util.Collections;

public class RedisLockUtil {

    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";

    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 系统启动时初始化
     */
    public static Jedis getJedis() {
        Jedis jedis = null;
        if (jedis == null) {
            synchronized (RedisLockUtil.class) {
                if (jedis == null) {
                    jedis = new Jedis("localhost");
                }
            }
        }
        return jedis;
    }


    /**
     * 获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param value 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean getDistributedLock(Jedis jedis, String lockKey, String value, int expireTime) {
        String result = jedis.set(lockKey, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            System.out.println("get redis distributed lock success ......");
            return true;
        }
        System.out.println("get redis distributed lock fail ......");
        return false;
    }

    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param value 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String value) {
        boolean result = false;
        if(jedis != null){
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object object = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(value));
            if (RELEASE_SUCCESS.equals(object)) {
                System.out.println("execute lua script success ......");
                return true;
            }
        }
        return false;
    }

    /**
     * @param key   锁名
     * @param value 锁值
     * @return
     */
    public static boolean releaseLock(String key, String value) {
        return value.equals(getJedis().get(key)) && getJedis().del(key).equals(RELEASE_SUCCESS);
    }
}

测试下redis锁:

package com.example.demo.redis;

import redis.clients.jedis.Jedis;

import java.util.UUID;

public class RedisLockTest {


    public static void main(String[] args) {
        Jedis jedis = RedisLockUtil.getJedis();
        String lockKey = "REDIS_LOCK_KEY";
        String value = UUID.randomUUID().toString();
        try{
            if(RedisLockUtil.getDistributedLock(jedis, lockKey, value, 20000)){
                System.out.println("redis lock ......");
            }
        }catch (Exception e){
            System.out.println("redis lock exception ......");
        }finally {
            RedisLockUtil.releaseDistributedLock(jedis, lockKey, value);
        }
    }
}

测试结果:

get redis distributed lock success ......
redis lock ......
execute lua script success ......
release distributed lock success ......
posted @ 2019-07-12 17:18  逐日也桂圆  阅读(505)  评论(0编辑  收藏  举报