Redis+Lua脚本实现的分布式锁的正确操作

大家都知道我们的jdk锁和syncronized同步锁都是基于单jvm的,但是在分布式系统中由于应用部署在多台服务器
我们要实现跟单jvm一样的原子化效果必须依赖于应用服务器以外的节点,所以目前用的最多的便是利用redis和zookeeper实现的分布式锁,今天我们主要看下利用redis如何操作。
上代码:

import redis.clients.jedis.Jedis;
import java.util.Collections;

/**
 * 利用jedis实现的redis分布式锁
 *
 * NX:表示set方法启用NX模式(SET_IF_NOT_EXIST)即如果存在key不做操作,否则执行set操作
 * PX:表示给set的key值设置一个过期时间(SET_WITH_EXPIRE_TIME)
 * 这里要注意requestId这个参数,很重要,在加锁和解锁的过程都需要同一个requestId,即解铃还须系铃人的道    理。
 * 也可以将这个值放进ThreadLocal里边进行传递。
 */
public class RedisTool {

    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;

    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }
    
    

    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

        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(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

}

释放锁的时候我们借助Lua脚本封装了一个原子化操作:获取锁的值key的值进行比对,如果一致删除这个key否则返回0,结束。

你可能感兴趣的:(Redis+Lua脚本实现的分布式锁的正确操作)