第一种
原文地址
https://www.jb51.net/article/147617.htm
***
* 第一种Redis 分布式锁
*/
class CommonRedisHelper {
public static final String LOCK_PREFIX = "redis_lock";
public static final int LOCK_EXPIRE = 300; // ms
@Autowired
RedisTemplate redisTemplate;
/**
* 最终加强分布式锁
*
* @param key key值
* @return 是否获取到
*/
public boolean lock(String key) {
String lock = LOCK_PREFIX + key;
// 利用lambda表达式
return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
if (acquire) {
return true;
} else {
byte[] value = connection.get(lock.getBytes());
if (Objects.nonNull(value) && value.length > 0) {
long expireTime = Long.parseLong(new String(value));
if (expireTime < System.currentTimeMillis()) {
// 如果锁已经过期
byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
// 防止死锁
return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
}
}
}
return false;
});
}
/**
* 删除锁
*
* @param key
*/
public void delete(String key) {
redisTemplate.delete(key);
}
// 测试
public static void main(String[] args) {
String key = "1";
CommonRedisHelper redisHelper = new CommonRedisHelper();
boolean lock = redisHelper.lock(key);
if (lock) {
// 执行逻辑操作
redisHelper.delete(key);
} else {
// 设置失败次数计数器, 当到达5次时, 返回失败
int failCount = 1;
while (failCount <= 5) {
// 等待100ms重试
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (redisHelper.lock(key)) {
// 执行逻辑操作
redisHelper.delete(key);
} else {
failCount++;
}
}
throw new RuntimeException("现在创建的人太多了, 请稍等再试");
}
}
}
/***
*
*
* 注意事项:
*
* 1、获取锁时设置key的value值需要保持一定的唯一性,以识别是否是加锁和解锁的线程
*
* 2、key对应设置生命周期expireTime,防止死锁
*
*/
第二种
原文地址
https://blog.csdn.net/weixin_43952575/article/details/123000060
/**
* 设置等待时间,在时间内 循环操作 第二种
*/
@Component
class RedisLockUtilWithWaittime {
@Autowired
private RedisTemplate redisTemplate;
public static final String LOCKED = "TRUE";
public static final long EXPIRE = 120L;
public static final long ONE_MILLI_NANOS = 1000000L;
public static final long DEFAULT_TIME_OUT = 2000L;
public static final Random RANDOM = new Random();
public RedisLockUtilWithWaittime() {
}
// 函数式接口
public interface MainOperator<T> {
boolean HOLD_LOCK_TAG = false;
T executeInvokeLogic(boolean result) throws Exception;
}
// 等待时间重复获取
public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey, long milliTimeout) throws Exception {
try {
if (operator != null && lockCacheKey != null && milliTimeout >= 0L) {
boolean locked = false;
long startNano = System.nanoTime();
boolean waitFlag = milliTimeout > 0L;
long nanoTimeOut = (waitFlag ? milliTimeout : 50L) * 1000000L;
T resultObj = null;
try {
while (System.nanoTime() - startNano < nanoTimeOut) {
if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.SECONDS)) {
locked = true;
break;
}
if (!waitFlag) {
break;
}
Thread.sleep(30L, RANDOM.nextInt(500));
}
resultObj = operator.executeInvokeLogic(locked);
} catch (Exception ex) {
throw ex;
} finally {
if (locked) {
releaseRedisLock(lockCacheKey);
}
}
return resultObj;
} else {
throw new Exception("参数不合法");
}
} catch (Exception e) {
throw e;
}
}
/**
* @deprecated
*/
// 不推荐使用
@Deprecated
public <T> T executeSynchOperate(MainOperator<T> operator, String lockCacheKey) throws Exception {
boolean locked = false;
T resultObj = null;
try {
if (redisTemplate.opsForValue().setIfAbsent(lockCacheKey, LOCKED, 120L, TimeUnit.MICROSECONDS)) {
locked = true;
}
resultObj = operator.executeInvokeLogic(locked);
} catch (Exception ex) {
throw ex;
} finally {
if (locked) {
releaseRedisLock(lockCacheKey);
}
}
return resultObj;
}
/**
* 释放锁
*
* @param cacheKey
*/
public boolean releaseRedisLock(final String cacheKey) {
Boolean deleteLock = redisTemplate.delete(cacheKey);
if (Boolean.TRUE.equals(deleteLock)) {
return true;
}
return false;
}
public static void main(String[] args) {
/***
* 使用测试
*/
/**
* 在时间范围内重复执行操作,直到成功
* @return
* @throws Exception
*/
RedisLockUtilWithWaittime redisLockUtilWithWaittime = new RedisLockUtilWithWaittime();
String localKey = "myTest_1";
try {
String s = redisLockUtilWithWaittime.executeSynchOperate(result -> {
if (!result) {
throw new Exception("");
}
// 数据库逻辑
return "ww";
}, localKey, 5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
第三种
原文地址
https://blog.csdn.net/long2010110/article/details/82911168?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2-82911168-blog-123393216.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-2-82911168-blog-123393216.pc_relevant_default&utm_relevant_index=5
/**
* 第三种
*/
class RedisLock {
@Autowired
static RedisTemplate redisTemplate;
private static final Long SUCCESS = 1L;
/**
* 获取锁
*
* @param lockKey
* @param value
* @param expireTime:单位-秒
* @return
*/
public static boolean getLock(String lockKey, String value, int expireTime) {
boolean ret = false;
try {
String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value, expireTime);
if (SUCCESS.equals(result)) {
return true;
}
} catch (Exception e) {
}
return ret;
}
/**
* 释放锁
*
* @param lockKey
* @param value
* @return
*/
public static boolean releaseLock(String lockKey, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
Long result = (Long) redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value);
if (SUCCESS.equals(result)) {
return true;
}
return false;
}
}
第四种
原文地址
https://blog.csdn.net/jf991804033/article/details/109382683?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165474058716780357210246%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165474058716780357210246&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogbaidu_landing_v2~default-1-109382683-null-null.nonecase&utm_term=redistemplate+%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&spm=1018.2226.3001.4450
class RedisLockUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 获取锁的超时时间
*/
private static final long timeout = 300;
/**
* 加锁,无阻塞
*
* @param key
* @param expireTime
* @param value 存入Redis 值 推荐使用 uuid
* @return
*/
public Boolean lock(String key, String value, long expireTime) {
String requestId = value;
Long start = System.currentTimeMillis();
//自旋,在一定时间内获取锁,超时则返回错误
for (; ; ) {
//Set命令返回OK,则证明获取锁成功
Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, requestId, expireTime,
TimeUnit.SECONDS);
if (ret) {
return true;
}
//否则循环等待,在timeout时间内仍未获取到锁,则获取失败
long end = System.currentTimeMillis() - start;
if (end >= timeout) {
return false;
}
}
}
/**
* 删除缓存
* *
*
* @param key 可以传一个值 或多个 建议与lun脚本一起使用
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
public static void main(String[] args) {
/**
* 锁的key前缀
*/
String lockStr = "r_lock_";
/**
* 获取锁最大失败次数
*/
int maxFailCount = 5;
RedisLockUtils redisLockUtils =new RedisLockUtils();
String key = "test";
// 锁的过期时间,避免死锁,根据业务调整,毫秒
long expireTime = 1000;
//判断是否获得锁
boolean lock = redisLockUtils.lock(lockStr,UUID.randomUUID().toString(), expireTime);
if (lock) {
try {
//处理业务的方法
//TODO
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
redisLockUtils .del(lockStr);
}
} else {
int failCount = 1;
while (failCount <= maxFailCount) {
//判断是否获得锁
if ( redisLockUtils.lock(lockStr,UUID.randomUUID().toString(), expireTime) ){
//处理业务的方法
//TODO
//解锁
redisLockUtils .del(lockStr);
} else {
failCount++;
}
}
throw new RuntimeException("当前创建的数量太多了,请稍后再试。");
}
}
}
第五种
原文地址
https://blog.csdn.net/lzq199528/article/details/103421826?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165474165516780366537860%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165474165516780366537860&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-10-103421826-null-null.nonecase&utm_term=redistemplate+%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&spm=1018.2226.3001.4450
class RedisImpl {
@Autowired
public RedisTemplate redisTemplate;
// @Scheduled(cron = "* * * * * ?")
// public void test() {
// // 模仿多服务
// System.out.println("======================================================");
// new Thread(() -> redisLock("线程1")).start();
// new Thread(() -> redisLock("线程2")).start();
// new Thread(() -> redisLock("线程3")).start();
// new Thread(() -> redisLock("线程4")).start();
// }
public void redisLock(String threadName) {
boolean bol = getLock("aa");
if (bol) {
try {
// 执行业务
System.out.println(threadName + "执行业务");
} finally {
unlock("aa");
}
} else {
// 并发执行了
System.out.println("有服务器正在执行此次无需再次执行");
}
}
// 获得锁 ture 获得锁 false 没有获得锁
public Boolean getLock(String key) {
// 创建事物 防止命令执行一半
redisTemplate.multi();
redisTemplate.execute(
(RedisCallback<Boolean>) conn -> {
try {
conn.setNX(redisTemplate.getStringSerializer().serialize(key),
redisTemplate.getStringSerializer().serialize(key));
} finally {
// 关闭释放链接
conn.close();
}
return null;
});
// 防止死锁。 10秒后删除key
redisTemplate.expire(key, 10, TimeUnit.SECONDS);
List<Object> list = redisTemplate.exec();
return (Boolean) list.get(0);
}
// 释放锁
private void unlock(String key) {
redisTemplate.delete(key);
}
}
第六种
原文地址
https://blog.csdn.net/qq_34560135/article/details/113556357?ops_request_misc=&request_id=&biz_id=102&utm_term=redistemplate%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&utm_medium=distribute.pc_search_result.none-task-blog-2blogsobaiduweb~default-2-113556357.nonecase&spm=1018.2226.3001.4450
class RedisLockUtil {
private static ThreadLocal<Thread> THREA_LOCAL = new ThreadLocal<>();
private final String lock_prefix = "lock_prefix:";
@Autowired
private RedisTemplate<String, String> redisTemplate;
/** 加锁
* @param lock 锁 的key
* @param timeoutSeconds
* @return
* @throws InterruptedException
*/
public String lock(String lock, long timeoutSeconds) throws InterruptedException {
try {
String identification = UUID.randomUUID().toString();
String lockName = String.format("%s%s", lock_prefix, lock);
Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockName, identification, timeoutSeconds, TimeUnit.SECONDS);
if (flag) {
// 续签
Thread renewal = new Thread(new RenewalLock(lock, identification, timeoutSeconds));
renewal.setDaemon(true);
THREA_LOCAL.set(renewal);
renewal.start();
return identification;
}
} finally {
// 加锁失败处理
}
return "";
}
/** 释放锁
* @param lock
* @param identification
*/
public void release(String lock, String identification) {
try {
redisTemplate.setEnableTransactionSupport(true);
String lockName = String.format("%s%s", lock_prefix, lock);
redisTemplate.watch(lockName);
String identificationDB = redisTemplate.opsForValue().get(lockName);
if (identificationDB != null && identification != null && identification.equals(identificationDB)) {
redisTemplate.multi();
redisTemplate.delete(lockName);
redisTemplate.exec();
}
redisTemplate.unwatch();
} finally {
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
THREA_LOCAL.get().interrupt();
THREA_LOCAL.remove();
}
}
/**
* 续签lock
*/
private class RenewalLock implements Runnable {
private String lockName;
private String identification;
private Long timeout;
public RenewalLock(String lock, String identification, Long timeout) {
this.lockName = lock_prefix + lock;
this.identification = identification;
this.timeout = timeout;
}
@Override
public void run() {
int i = 0;
while (true) {
try {
if (Thread.currentThread().isInterrupted()) {
return;
}
TimeUnit.SECONDS.sleep(timeout / 2);
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.watch(lockName);
String identificationDB = redisTemplate.opsForValue().get(lockName);
if (identificationDB != null && identification != null && identificationDB.equals(identification)) {
redisTemplate.multi();
redisTemplate.expire(lockName, timeout, TimeUnit.SECONDS);
redisTemplate.exec();
}
redisTemplate.unwatch();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Thread.currentThread().interrupt();
} finally {
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
}
}
}
}
}