redis中的分布式锁有哪些特点

66次阅读
没有评论

共计 2683 个字符,预计需要花费 7 分钟才能阅读完成。

本篇内容主要讲解“redis 中的分布式锁有哪些特点”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“redis 中的分布式锁有哪些特点”吧!

分布式锁的特点

1. 独占性

不论在任何情况下都只能有一个线程持有锁。

2. 高可用

redis 集群环境不能因为某一个节点宕机而出现获取锁或释放锁失败。

3. 防死锁

必须有超时控制机制或者撤销操作。

4. 不乱抢

自己加锁,自己释放。不能释放别人加的锁。

5. 重入性

同一线程可以多次加锁。

redis 单机怎么实现

一般情况下都是使用 setnx+lua 脚本实现。

直接贴代码

package com.fandf.test.redis;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
 * redis  单机锁
 *
 * @author fandongfeng
 * @date 2023/3/29 06:52
 */
@Slf4j
@Service
public class RedisLock {
 @Resource
 RedisTemplate String, Object  redisTemplate;
 private static final String SELL_LOCK =  kill: 
 /**
 *  模拟秒杀
 *
 * @return  是否成功
 */
 public String kill() {
 String productId =  123 
 String key = SELL_LOCK + productId;
 // 锁 value, 解锁时   用来判断当前锁是否是自己加的
 String value = IdUtil.fastSimpleUUID();
 // 加锁   十秒钟过期   防死锁
 Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, value, 10, TimeUnit.SECONDS);
 if (!flag) {
 return  加锁失败 
 }
 try {
 String productKey =  good123 
 // 获取商品库存
 Integer stock = (Integer) redisTemplate.opsForValue().get(productKey);
 if (stock == null) {
 // 模拟录入数据,  实际应该加载时从数据库读取
 redisTemplate.opsForValue().set(productKey, 100);
 stock = 100;
 }
 if (stock  = 0) {
 return  卖完了,下次早点来吧 
 }
 // 扣减库存,  模拟随机卖出数量
 int randomInt = RandomUtil.randomInt(1, 10);
 redisTemplate.opsForValue().decrement(productKey, randomInt);
 //  修改 db, 可以丢到队列里慢慢处理
 return  成功卖出  + randomInt +  个,库存剩余  + redisTemplate.opsForValue().get(productKey) +  个 
 } finally {
// // 这种方法会存在删除别人加的锁的可能
// redisTemplate.delete(key);
// if(value.equals(redisTemplate.opsForValue().get(key))){
// // 因为 if 条件的判断和  delete 不是原子性的,// //if 条件判断成功后,恰好锁到期自己解锁
// // 此时别的线程如果持有锁了,就会把别人的锁删除掉
// redisTemplate.delete(key);
// }
 // 使用 lua 脚本保证判断和删除的原子性
 String luaScript =
  if (redis.call( get ,KEYS[1]) == ARGV[1]) then   +
  return redis.call(del ,KEYS[1])   +
  else   +
  return 0   +
  end 
 redisTemplate.execute(new DefaultRedisScript (luaScript, Boolean.class), Collections.singletonList(key), value);
 }
 }

}

进行单元测试,模拟一百个线程同时进行秒杀

package com.fandf.test.redis;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT;
 * @Description:
 * @author: fandongfeng
 * @date: 2023-3-24 16:45
 */
@SpringBootTest
class SignServiceTest {
 
 @Resource
 RedisLock redisLock;

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计2683字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)