public static boolean lock(String preCode, int expire) throws InterruptedException {
JedisCluster jedisCluster = JedisClusterUtil.getInstance().getJedisCluster();
Long beginTime = System.currentTimeMillis();
long expires = System.currentTimeMillis() + expire + 1;
do{
if(jedisCluster.setnx(preCode, String.valueOf(expires))==1){
return true;
}else {
String currentValueStr = jedisCluster.get(preCode); //redis里的时间
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
String oldValueStr = jedisCluster.getSet(preCode, String.valueOf(expires));
//获取上一个锁到期时间,并设置现在的锁到期时间,
//只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
return true;
}
}
Thread.sleep(100);
}
}while((System.currentTimeMillis() - beginTime) < expire);
return false;
}
public static void unLock(String preCode) {
JedisCluster jedisCluster = JedisClusterUtil.getInstance().getJedisCluster();
jedisCluster.del(preCode);
}
以上实现需要要求所有机器的时钟一致。
以下可以通过lua脚本的方式
// “自旋”,等待锁
static boolean lock(String key, String value,long exprie){
// 申请锁,只有当“key”不存在时才能申请成功,返回“OK",锁的过期时间设置为exprie秒
//String result = jedis.set(key, value, NX, PX, exprie);
JedisCluster jedisCluster = JedisClusterUtil.getInstance().getJedisCluster();
String result = (String) jedisCluster.eval("return redis.call('set', KEYS[1],ARGV[1],'nx', 'ex', ARGV[2]) ", Collections.singletonList(key), Arrays.asList(value, exprie+""));
if ("OK".equals(result))
{
return true;
}
return false;
}
// Lua脚本,用于校验并释放锁
static boolean unlock(String key, String value){
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
// 执行Lua脚本,校验并释放锁
JedisCluster jedisCluster = JedisClusterUtil.getInstance().getJedisCluster();
return 1L==jedisCluster.eval(script, Collections.singletonList(key),
Collections.singletonList(value));
}
jar依赖如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>