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 ......