com.lx.boot.lock.RedisLock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lxboot3 Show documentation
Show all versions of lxboot3 Show documentation
使用文档: https://a7fi97h1rc.feishu.cn/docx/X3LRdtLhkoXQ8hxgXDQc2CLOnEg?from=from_copylink
package com.lx.boot.lock;
import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.util.LX;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Slf4j
public class RedisLock {
private StringRedisTemplate stringRedisTemplate;
//redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("META-INF/lua/redis-limit.lua")));
/**
* 加/解锁的lua脚本
*/
public static final String LOCK_LUA;
public static final String UNLOCK_LUA;
static {
//判断key是否存在 判断值对不对 对+1
StringBuilder sb = new StringBuilder();
sb.append("if redis.call('exists',KEYS[1]) == 0 ");
sb.append("then ");
sb.append(" redis.call('hincrby' ,KEYS[1] ,ARGV[1] ,1) ");
sb.append(" redis.call('expire' ,KEYS[1] ,ARGV[2]) ");
sb.append(" return 1 ");
sb.append("end ");
sb.append("if redis.call('hexists',KEYS[1], ARGV[1]) == 1 ");
sb.append("then ");
sb.append(" redis.call('hincrby' ,KEYS[1] ,ARGV[1] ,1) ");
sb.append(" redis.call('expire' ,KEYS[1] ,ARGV[2]) ");
sb.append(" return 1 ");
sb.append("end ");
sb.append("return 0 ");
LOCK_LUA = sb.toString();
//判断值是否一致 次数减少 如果次数为0 则删除键
sb = new StringBuilder();
sb.append("if redis.call('hexists',KEYS[1], ARGV[1]) == 0 then ");
sb.append("return 0 ");
sb.append("end ");
sb.append("if redis.call('hincrby' ,KEYS[1] ,ARGV[1] ,-1) > 0 then ");
sb.append(" redis.call('expire' ,KEYS[1] ,ARGV[2]) ");
sb.append("else ");
sb.append(" redis.call('del' ,KEYS[1])");
sb.append("end ");
sb.append("return 1 ");
UNLOCK_LUA = sb.toString();
}
/**
* 锁标志对应的key
*/
private String lockKey;
/**
* 锁对应的值
*/
private String lockValue;
/**
* 锁的有效时间(s)
*/
private int expireTime = 60;
final Random random = new Random();
public int getExpireTime() {
return expireTime;
}
public void setExpireTime(int expireTime) {
this.expireTime = expireTime<10?10:expireTime;
}
/**
* 使用默认的锁过期时间和请求锁的超时时间
*
* @param redisTemplate
* @param lockKey 锁的key(Redis的Key)
*/
RedisLock(StringRedisTemplate stringRedisTemplate, String lockKey) {
this.stringRedisTemplate = stringRedisTemplate;
this.lockKey = lockKey + "_lock";
this.lockValue = OS.getLogTraceId();
if (this.lockValue == null){
this.lockValue = LX.uuid32(10);
}
}
/**
* 使用默认的请求锁的超时时间,指定锁的过期时间
*
* @param redisTemplate
* @param lockKey 锁的key(Redis的Key)
* @param expireTime 锁的过期时间(单位:秒)
*/
RedisLock(StringRedisTemplate stringRedisTemplate, String lockKey, int expireTime) {
this(stringRedisTemplate, lockKey);
setExpireTime(expireTime);
}
@Note("尝试获取锁 超时返回")
public boolean tryLock(long timeout) {
// 系统当前时间,毫秒
long nowTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - nowTime) < timeout) {
if (this.lock()) {
// 上锁成功结束请求
return true;
}
// 每次请求等待一段时间
sleep(100, 50000);
}
return false;
}
@Note("尝试获取锁 立即返回")
public boolean lock() {
List keys = new ArrayList<>();
keys.add(lockKey);
DefaultRedisScript redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(LOCK_LUA);
redisScript.setResultType(Long.class);
Long result = (Long) stringRedisTemplate.execute(redisScript, keys, lockValue , expireTime+"");
if (result == 1){
log.debug("分布式锁-加锁:"+lockKey+" "+stringRedisTemplate.opsForHash().get(lockKey,lockValue));
}
return result == 1;
}
@Note("以阻塞方式的获取锁")
public boolean lockBlock() {
while (true) {
//不存在则添加 且设置过期时间(单位ms)
if (lock()) {
return true;
}
// 每次请求等待一段时间
sleep(100, 50000);
}
}
@Note("解锁")
public boolean unlock() {
List keys = new ArrayList<>();
keys.add(lockKey);
DefaultRedisScript redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(UNLOCK_LUA);
redisScript.setResultType(Long.class);
Long result = (Long) stringRedisTemplate.execute(redisScript, keys, lockValue , expireTime+"");
if (result == 1) {
log.debug("分布式锁-解锁:" + lockKey + " " + stringRedisTemplate.opsForHash().get(lockKey,lockValue));
}
return result == 1;
}
/**
* 线程等待时间
*
* @param millis 毫秒
* @param nanos 纳秒
*/
private void sleep(long millis, int nanos) {
try {
Thread.sleep(millis, random.nextInt(nanos));
} catch (InterruptedException e) {
log.debug("获取分布式锁休眠被中断:", e);
Thread.currentThread().interrupt();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy