概述
分布式锁框架--Redisson
- 一.Redisson简介
- 1. redisson概述
- 2.整合Redisson
- 1).依赖
- 2).Redisson配置
- 2.1)redisson配置文件
- 二、Redisson完成分布式锁功能
- 1.分布式锁和同步器
- 1.1. 可重入锁(Reentrant Lock)*
- 1).测试-分布式--lock
- a.优点:自动续期、自动解锁
- b.手动设置 锁的过期时间
- c.最佳实践
- 2)trylock
- 1.2 公平锁(Fair Lock)
- 1.3 读写锁(ReadWriteLock)*
- 1).原理: 读好像无锁,写有锁
- 2).介绍
- 3).代码--写锁、读锁
- a.写锁
- b.读锁
- 优点:一定能读到最新数据修改期间,写锁是排它锁(互斥锁、独享锁),读锁是共享锁。写锁没释放,读锁必须对待
- 4).场景模拟
- a.读+读
- b.写+读,必须等待写锁完成
- c.写+写,阻塞状态
- d.读+写。有读锁,写锁需等待
- 总结:只要有写锁,必须等待(读锁是共享锁,写锁是互斥锁)
- 1.4 信号量(Semaphore)*
- 1).原理: 释放release后,才能获得acquire
- 2).介绍
- 3) 场景 车辆入库、出库
- 4) 代码
- 1.5 闭锁(CountDownLatch)
- 1).原理: 计数器为0,才闭锁
- 2).介绍
- 3). 场景-学校锁门
- 4).代码
- 5).测试
- 6).总结: 闭锁,必须在计数为0,才闭锁
- 1.6 使用JUC也可以实现以上逻辑
Redisson的github地址
Redisson的github的文档
官网地址
一.Redisson简介
1. redisson概述
redisson概述
2.整合Redisson
1).依赖
依赖
<!--使用redisson作为所有分布式锁,分布式对象等功能性框架-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
2).Redisson配置
a.配置方法
b.第三方框架整合
c. 单Redis节点模式 --redis不是集群
单Redis节点模式
2.1)redisson配置文件
@Configuration
public class MyRedissonConfig {
//所有对Redisson的使用,都是RedissonClient对象
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException {
//错误: Redis url should start with redis:// or rediss:// (for SSL connection)
//1.创建配置
Config config = new Config();
//设置单节点模式
config.useSingleServer().setAddress("redis://192.168.56.10:6379");
//2.根据Config创建出RedissonClient实例
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
二、Redisson完成分布式锁功能
分布式对象
分布式集合
分布式锁和同步器
1.分布式锁和同步器
1.1. 可重入锁(Reentrant Lock)*
基于Redis的Redisson分布式 可重入锁RLock
Java对象实现了java.util.concurrent.locks.Lock接口。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。RLock lock = redisson.getLock(“anyLock”); // 最常见的使用方法 lock.lock();
解锁
另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
// 加锁以后10秒钟自动解锁
// 无需调用unlock方法手动解锁
lock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
…
} finally {
lock.unlock();
}
}
1).测试-分布式–lock
分布式测试product,启动10000,10001
http://localhost:10000/hello,
http://localhost:10001/hello
@ResponseBody
@GetMapping("/hello")
private String hello() {
//1.获取一把锁,只要锁名一样,就是同一把锁
RLock lock = redisson.getLock("my-lock");
//2.加锁(默认过期时间30s)
lock.lock();//阻塞式等待
//1).锁的自动续期(如果业务超长,会自动给锁加上30s。防止业务时间长,锁自动过期被删除)
//2).加锁业务只要运行完成,不会给当前锁续期;若不解锁,锁默认30s后自动解锁
try {
System.out.println("加锁成功,执行业务 "+Thread.currentThread().getId());
Thread.sleep(10000);
} catch (Exception e) {
} finally {
//3.解锁--假如解锁异常,redis会不会死锁?
System.out.println("释放锁,"+Thread.currentThread().getId());
lock.unlock();
}
return "hello";
}
a.优点:自动续期、自动解锁
b.手动设置 锁的过期时间
问题:
如果过期时间小于业务执行时间,会出现异常(因为解锁的不是自己的锁)
attempt to unlock lock, not locked by current thread by node id: 1e679a77-58f9-4e9a-a3ad-8007086d665d thread-id: 105
原理:
c.最佳实践
设置时间30秒
2)trylock
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
1.2 公平锁(Fair Lock)
RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();
1.3 读写锁(ReadWriteLock)*
读写锁(ReadWriteLock)
1).原理: 读好像无锁,写有锁
2).介绍
基于Redis的Redisson分布式可重入读写锁RReadWriteLock
Java对象实现了java.util.concurrent.locks.ReadWriteLock接口。其中读锁和写锁都继承了RLock接口。
分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
指定加锁的时间。超过这个时间后锁便自动解开了。
// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 或
rwlock.writeLock().lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// 或
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
3).代码–写锁、读锁
a.写锁
//读写锁(ReadWriteLock)--允许同时有多个读锁和一个写锁处于加锁状态。
@ResponseBody
@GetMapping("/write")
public String writeValue() {
//1.写操作,加写锁
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
RLock rLock = lock.writeLock();//写锁
String s = null;
try {
//写锁
rLock.lock();
s = UUID.randomUUID().toString();
Thread.sleep(10000);
redisTemplate.opsForValue().set("writeValue",s);
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
rLock.unlock();
}
return s;
}
b.读锁
@ResponseBody
@GetMapping("/read")
public String readValue() {
//1.读操作,加读锁
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
RLock rLock = lock.readLock();//读锁
//加读锁
rLock.lock();
String s =null;
try {
s= (String) redisTemplate.opsForValue().get("writeValue");
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
rLock.unlock();
}
return s;
}
优点:一定能读到最新数据修改期间,写锁是排它锁(互斥锁、独享锁),读锁是共享锁。写锁没释放,读锁必须对待
4).场景模拟
a.读+读
相当于无锁,并发读,只会在redis记录所有当前读锁,他们会同时加锁成功
直接访问2个读
b.写+读,必须等待写锁完成
读锁必须在写锁完成,才能读
先访问写操作,再访问读操作
c.写+写,阻塞状态
写锁是阻塞状态,写+写还是阻塞状态
先访问一个写,再访问一个写操作
d.读+写。有读锁,写锁需等待
先访问读操作,再访问写操作
总结:只要有写锁,必须等待(读锁是共享锁,写锁是互斥锁)
1.4 信号量(Semaphore)*
信号量(Semaphore)
1).原理: 释放release后,才能获得acquire
2).介绍
基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。
RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();//阻塞队列
//或
semaphore.acquireAsync();
semaphore.acquire(23);
semaphore.tryAcquire();//非阻塞队列
//或
semaphore.tryAcquireAsync();
semaphore.tryAcquire(23, TimeUnit.SECONDS);
//或
semaphore.tryAcquireAsync(23, TimeUnit.SECONDS);
semaphore.release(10);
semaphore.release();
//或
semaphore.releaseAsync();
3) 场景 车辆入库、出库
车辆出库,车位才可以入库 没有出库,没有车位,入库失败
4) 代码
//信号量
/**
* 停车入库
* 3号位
* 信号量可以作为分布式限流
*/
@ResponseBody
@GetMapping("/park")
//停车(车辆入库)
public String park() {
RSemaphore park = redisson.getSemaphore("park");
// try {
// park.acquire();//获取一个信号,获取一个值,占一个车位 (阻塞队列)
// System.out.println("车辆入库成功。。。");
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
boolean b = park.tryAcquire();//非阻塞队列
if (b) {
//执行业务
System.out.println("车辆入库成功。。。");
} else {
System.out.println("车辆入库失败。。。");
return "error";
}
return "ok=>" + b;
// return "ok";
}
//开走车
@ResponseBody
@GetMapping("/go")
//车辆出库
public String go() {
RSemaphore park = redisson.getSemaphore("park");
//释放一个车位
park.release();
System.out.println("释放车位成功。。。");
return "ok";
}
1.5 闭锁(CountDownLatch)
1).原理: 计数器为0,才闭锁
2).介绍
基于Redisson的Redisson分布式闭锁(CountDownLatch)Java对象RCountDownLatch采用了与java.util.concurrent.CountDownLatch相似的接口和用法。
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();
// 在其他线程或其他JVM里
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();
3). 场景-学校锁门
只有全部班级走,才能锁门
4).代码
// 闭锁(CountDownLatch)
/*
* 放假,锁门
*1班没人了
* 5个班全部走完,才能锁门
* */
@ResponseBody
@GetMapping("/lockDoor")
//场景:
public String lockDoor() {
RCountDownLatch door = redisson.getCountDownLatch("door");
door.trySetCount(5);
try {
door.await();//等待闭锁完成
System.out.println("放假了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "放假了。。。";
}
@ResponseBody
@GetMapping("/gogo/{id}")
public String gogo(@PathVariable("id") Long id){
RCountDownLatch door = redisson.getCountDownLatch("door");
door.countDown();//计数减一
System.out.println(id+" 班的人都走了。。。");
return id+" 班的人都走了。。。";
}
5).测试
http://localhost:10000/lockDoor
http://localhost:10000/gogo/1
http://localhost:10000/gogo/2
http://localhost:10000/gogo/3
http://localhost:10000/gogo/4
http://localhost:10000/gogo/5
6).总结: 闭锁,必须在计数为0,才闭锁
1.6 使用JUC也可以实现以上逻辑
最后
以上就是无限绿茶为你收集整理的分布式锁框架--Redisson一.Redisson简介二、Redisson完成分布式锁功能的全部内容,希望文章能够帮你解决分布式锁框架--Redisson一.Redisson简介二、Redisson完成分布式锁功能所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复