参考链接:https://www.bilibili.com/video/BV1Rv41177Af?p=43&spm_id_from=pageDriver
1、刚开始 可以使用sexnx 这个命令上锁。。。使用完毕删除该key释放锁
2、使用setnx出现问题,使用sexnx一直不释放锁。怎么办?可以给锁加一个过期时间。
3、使用setnx 之后,准备设置过期时间。但是不能设置过期时间。怎么办?同时上锁的时候,同时设置过期时间 set key1 vvvv1 nx ex 12 #设置key1 值是vvvv1 过期时间是12秒
4、锁的释放问题
5、锁的UUID一样之后,还能删锁问题
6、锁的特点
互斥性:相互互斥
不发生死锁
各自释放各自的锁
加锁解锁有原子性
先测试1:加锁操作值释放锁。没有获得锁就等待
application.properties
spring.redis.cluster.nodes=192.168.181.138:7001, 192.168.181.138:7002,192.168.181.138:7003,192.168.181.138:7004,192.168.181.138:7005,192.168.181.138:7006
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=5
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=6000
config
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Serializable>redisTemplate(LettuceConnectionFactory connectionFactory) {RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}
}
controller
@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}
}
测试:
1、先在redis中 set num 0
2、linux安装ab工具: yum -y install httpd-tools #安装ab工具 ab -V 查看版本
3、启动服务,开始测试
#测试命令 ab -n 1000 -c 100 http://192.168.124.8:8080/block
-c100 表示并发用户数为100
-n1000 表示请求总数为1000
查看结果:
在redis中 get num #输出num的值是1000
在测试2,使用setnx出现问题,使用sexnx一直不释放锁。怎么办?可以给锁加一个过期时间。
application.properties
spring.redis.cluster.nodes=192.168.181.138:7001, 192.168.181.138:7002,192.168.181.138:7003,192.168.181.138:7004,192.168.181.138:7005,192.168.181.138:7006
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=5
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=6000
config
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Serializable>redisTemplate(LettuceConnectionFactory connectionFactory) {RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}
}
controller
@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){
//设置10秒key过期Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111",10, TimeUnit.SECONDS);if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}}
4、锁的释放问题
0、abc是多个应用。需要操作同一个锁
1、a先操作、上锁成功、具体操作、操作过程中服务器卡顿等。。。锁的时间到了,自动释放
2、b抢到了锁,b开始上锁成功,b开始具体操作,md,现在a居然又正常了,执行代码释放锁。会把b的锁给释放掉
解决方案:
controller
package com.nuc.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Controller
public class DemoController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/block")@ResponseBodypublic void block(){String uuid =UUID.randomUUID().toString();Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,10, TimeUnit.SECONDS);if(lock){Object value = redisTemplate.opsForValue().get("num");if(StringUtils.isEmpty(value)){return;}int integer = Integer.valueOf(value+"");redisTemplate.opsForValue().set("num",integer+1);if(uuid.equals(redisTemplate.opsForValue().get("lock"))){redisTemplate.delete("lock");String name = Thread.currentThread().getName();System.out.println(name+"设置成功");}}else {try {Thread.sleep(100);String name = Thread.currentThread().getName();System.out.println(name+"开始进入等待======");block();} catch (InterruptedException e) {e.printStackTrace();}}}
}
5、锁的UUID一样之后,还能删锁问题
1、a上锁、具体操作、释放锁的时候先比较uui,发现uuid一样。开始删除的时候卡顿了。或锁的过期时间到了自动释放锁
2、在a卡顿或释放锁的时候b获得了锁,开始了具体操作
3、a卡顿之后要开始删除锁。导致a释放了b的锁。。
解决方案:加入lua脚本