redis实现分布式锁 1.锁的处理 2.分布式锁需要注意事项 3.获取锁 4.释放锁

  • 单应用中(单进程多线程情况)锁的处理:
    • synchronized
    • lock
  • 分布式应用中锁的处理:
    • 数据库乐观锁;
    • 基于zookeeper的分布式锁;
    • 基于redis的分布式锁

2.分布式锁需要注意事项

  • 互斥性: 在任意时刻,只有一个客户端能持有锁
  • 同一性:   加锁和解锁必须是同一个客户端,客户端自己不能把别的客户端加的锁给解了
  • 避免死锁:  即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁 

3.获取锁

方式一:使用set命令实现

redis实现分布式锁
1.锁的处理
2.分布式锁需要注意事项
3.获取锁
4.释放锁

 代码如下:

/**
     * 使用redis的set命令实现获取分布式锁
     * @param lockKey       可以就是锁
     * @param requestId        请求ID,保证同一性
     * @param expireTime    过期时间,避免死锁
     * @return
     */
    public static boolean getLock(String lockKey,String requestId,int expireTime) {
        //NX:保证互斥性
        String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
        if("OK".equals(result)) {
            return true;
        }
        
        return false;
    }
方式二:使用setnx命令,这里使用synchronized保证方法的原子性
1 public static synchronized boolean Lock2(String lockKey,String requestId,int expireTime) {
2         Long result = jedis.setnx(lockKey, requestId);
3         if(result == 1) {
4             jedis.expire(lockKey, expireTime);
5             return true;
6         }
7 
8         return false;
9     }

4.释放锁

方式一:使用del命令

    /**
     * 释放分布式锁
     * @param lockKey
     * @param requestId
     */
    public static void releaseLock(String lockKey,String requestId) {
        if (requestId.equals(jedis.get(lockKey))) {
            jedis.del(lockKey);
        }
    }

方式二:使用Lua脚本

public static boolean releaseLock(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 (result.equals(1L)) {
            return true;
        }
        return false;
    }