参考文档:https://github.com/redisson/redisson/wiki/8.-分布式锁和同步器
读写锁
//注入redisson
@Autowired
RedissonClient redisson;
//注入redis
@Autowired
StringRedisTemplate redisTemplate;
//没有引入依赖的请参照redis回顾 https://blog.csdn.net/qq_42604730/article/details/112727076引入依赖
//保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁,独享锁)。读锁是一个共享锁
//写锁没释放,读就必须等待
//读+读:相当于无锁,并发读,只会在redis记录好,所有当前的读锁。他们都会同时加锁成功
//写+读:等待写锁释放
//写+写:阻塞方式,下一个写锁必须等待上一个写锁释放
//读+写:有读锁。写也需要等待
//总结:只要有写的存在,都必须等待
//写方法
@ResponseBody
@GetMapping("/write")
public String writeValue(){
//获取读写锁
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
String s="";
//加写锁
RLock rLock = lock.writeLock();//拿到写锁
try {
//1、改数据加写锁,读数据加读锁
rLock.lock();
s = UUID.randomUUID().toString();
Thread.sleep(30000);//休眠30秒
redisTemplate.opsForValue().set("writeValue",s);//给redis存入一个值
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
rLock.unlock();//释放写锁
}
return s;
}
//读方法
@ResponseBody
@GetMapping("/read")
public String readValue(){
//拿到读写锁
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
String s="";
//加读锁
RLock rLock = lock.readLock();//拿到读锁
rLock.lock();//加锁
try {
s = redisTemplate.opsForValue().get("writeValue");//获取redis中的值
} catch (Exception e) {
e.printStackTrace();
}finally {
rLock.unlock();//释放读锁
}
return s;
}
测试:
1、在redis添加一个键值
调用请求读方法
调用请求写方法
写值成功,读值才能成功,写值一更改,读就必须等写锁释放。
信号量
例子: 车库停车,有3个车位,只要来一辆车,占用一个车位,走了一个释放一个车位,想停车要看车位够不够
/**
* 车库停车
* 3车位
* 信号量也可以用作分布式限流
*/
//停车请求,获取一个车位
@GetMapping("/park")
@ResponseBody
public String park() throws InterruptedException {
RSemaphore park = redisson.getSemaphore("park");
// park.acquire();//获取一个信号,获取一个值,占一个车位
//acquire()是阻塞式获取,相当于一定要获取车位
//park.tryAcquire()有车位就停,没有就算了,获取成功返回true否则返回false
boolean b = park.tryAcquire();
if (b){
//执行业务
}else {
return "error";
}
return "ok=>"+b;
}
//释放一个车位
@GetMapping("/go")
@ResponseBody
public String go() throws InterruptedException {
RSemaphore park = redisson.getSemaphore("park");
park.release();//释放一个车位
// Semaphore semaphore=new Semaphore(5);
// semaphore.release();
// semaphore.acquire();
return "ok";
}
测试,在redis中添加键为park,值为3
发送停车请求,redis中的信号量-1
当信号为0时再次发送停车请求,提示error,表示位置已占满
当进行释放请求,释放车位时,信号量回来
一般用做限流操作
闭锁
/**
* 放假,锁门
* 1班没人了、2
* 5个班全部走完,我们可以锁大门
*/
//锁门方法
@GetMapping("/lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {
RCountDownLatch door = redisson.getCountDownLatch("door");
//设置等待多少个班走完
door.trySetCount(5);
door.await();//等待闭锁都完成
return "放假了...";
}
//离开方法
@GetMapping("/gogogo/{id}")
public String gogogo(@PathVariable("id") Long id){
//获取闭锁
RCountDownLatch door = redisson.getCountDownLatch("door");
door.countDown();//计数减1
return id+"班的人都走了...";
}
调用锁门方法,一直在请求,因为是闭锁,有5个数,需要5个都走完
调用离开方法
走完之后,闭锁调用成功