侧边栏壁纸
博主头像
再见理想博主等级

只争朝夕,不负韶华

  • 累计撰写 112 篇文章
  • 累计创建 64 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Reids实现分布式锁原理

再见理想
2022-05-27 / 0 评论 / 0 点赞 / 462 阅读 / 735 字

一,Reids实现分布式锁原理

# 核心命令
setnx key value (set if not exist)

`只要key不存在,就保存key value;若存在,不操作。一个线程先拿到锁(setnx 保存key到value),其它线程再setnx key, 返回false。

对应代码:

redisTemplate.opsForValue().setIfAbsent(key, value)

保存成功返回true 失败返回false。注意:用完要释放锁。

使用注意:
1,线程拿到锁,业务逻辑抛异常,不能释放锁。
解决:把业务代码放进try catch finally。在finally释放锁。

2,线程拿到锁,突然服务挂了或网络问题,finally也不能执行,不能释放锁。
解决:设置key过期时间,set key时就传入过期时间。

3,高并发下,线程A进去业务逻辑 -> 线程A执行时间超过设置的过期时间 -> 这时释放了锁,线程B拿到锁,执行业务代码 -> 线程A此时执行完了,释放了B的锁,以此循环。

解决:线程A的key只能线程A删除。给每个线程一个UUID,作为 value 存入 redis,删除 key 前先校验 value。

代码:

	public void methodA(){
		String lockKey = "key";
		String clientId = UUID.randomUUID().toString();
		
		//设置锁,同时设置过期时间和唯一id。设置失败表示锁已被占用,返回错误信息。  
		Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey,  clientId, 10, TimeUnit.SECONDS); 
		if(!result){
			return "error";
		}
		
		try{
			...业务逻辑...
		}finally{
			//当前锁只能由当前线程释放
			if(clientId.equals(redisTemplate.opsForValue().get(lockKey))){
				redisTemplate.delete(lockKey);
			}
		}
	}

SpringBoot 整合 Redisson 工具更轻松帮我们解决以上的问题。

二,Redisson实现方式

1,添加依赖

	<!--redisson客户端 -->
	<dependency>
		<groupId>org.redisson</groupId>
		<artifactId>redisson</artifactId>
		<version>3.12.3</version>
	</dependency>

2,添加redisson配置文件

	@Configuration
	public class RedisConfiguration {
		@Value("${spring.redis.host}")
		private String redisHost;

		@Value("${spring.redis.password}")
		private String password;

		@Bean
		public Redisson redisson() {
			Config config = new Config();
			config.useSingleServer().setAddress("redis://" + redisHost + ":6379").setPassword(password).setDatabase(0);
			return (Redisson) Redisson.create(config);
		}
	}

3,使用

	@Autowired
		private Redisson redisson;
	
	public void methodA(){
		RLock redissonLock = redisson.getLock(unitId.toString());
		try {
			redissonLock.lock();   //上锁  还可以用tryLock()、tryInterruptibly()。下面有它们的区别
			...业务逻辑...
		}finally {
			redissonLock.unlock();  //释放锁
		}
	}

三,lock()、tryLock()、lockInterruptibly()区别

1,lock()

拿不到lock就不罢休,不然线程就一直block,比较无赖的做法。

2,tryLock()

马上返回,拿到lock就返回true,不然返回false。 带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false。

3,ryInterruptibly()

在锁上等待,直到获取锁,但是会响应中断,这个方法优先考虑响应中断,而不是响应锁的普通获取或重入获取。

0

评论区