前提:使用redis实现分布式锁
1.在pom文件中导入java对redis分布式锁的支持依赖:
<!-- 实现分布式锁依赖-->
<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.8</version>
</dependency>
2.编写配置类
@Configuration
public class MyRedissonConfig {
/**
* destroyMethod定义销毁方法
* @return
*/
@Bean(destroyMethod = "shutdown",value = "redisson")
RedissonClient getRedissonClient(){
//创建配置
Config config = new Config();
//这里的redis地址是你自己的
config.useSingleServer().setAddress("redis://158.72.233.198:6379");
//根据config创建出实例
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
3.分布式锁的原理
redis分布式锁与JUC的Lock锁的实现基本一致,lock()方法加锁,unlock()方法解锁
1.可重入锁(Reentrant Lock):如果在锁的内部有嵌套锁,并且是同一把锁的话,内部可以直接执行,即内部可以使用外部锁
@GetMapping("hello")
@ResponseBody
public String hello() {
//使用分布式锁,通过锁客户端->取得一把锁,并定义锁名字,只要锁的名字一致就是同一把锁
//RLock继承与lock
RLock lock = redisson.getLock("my-lock");
//加锁
//如果我们传递了锁的超时时间,就发送redis脚本,进行占锁,默认超时时间就是我们指定的时间
//如果我们没有传递锁超时时间,就使用看门狗的30*1000,后端会通过异步编排的定时器机制,发现线程还在运行,并且在10s,调用方法重新延时为30s
lock.lock();//这个加锁是阻塞式等待
//锁的自动续期,如果业务超长,每当运行到默认时间的/3,自动给锁续上30秒(看门狗机制)
try {
// 取得线程id
System.out.println("加锁成功,执行业务...."+Thread.currentThread().getId());
Thread.sleep(30000);
} catch (Exception e) {
e.printStackTrace();
}finally {
//解锁,此处即使代码没有运行也会解锁,因为看门狗机制
lock.unlock();
System.out.println("解锁成功...."+Thread.currentThread().getId());
}
return "hello";
}
2.公平锁(Fair Lock):它保证当多个redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程
@GetMapping("read")//读锁是共享锁
@ResponseBody
public String readValue(){
//获取读写锁对象
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
//获取读锁
RLock rLock = lock.readLock();
String s = "";
try {
rLock.lock();//加锁
s = stringRedisTemplate.opsForValue().get("writeValue");
} catch (Exception e) {
e.printStackTrace();
}finally {
rLock.unlock();//解锁
}
return s;
}
@GetMapping("write")//写锁是排他锁
@ResponseBody
public String writeValue(){
//获取读写锁对象
RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
//改数据用写锁
RLock rLock = lock.writeLock();
String s = "";
try {
rLock.lock();//加锁
s = UUID.randomUUID().toString().replaceAll("-","");
Thread.sleep(30000);
//将s放入到缓存中
stringRedisTemplate.opsForValue().set("writeValue",s);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
rLock.unlock();//解锁
}
return s;
}
4.信号量(Semaphore):基于redis的redisson的分布式信号量,类似于占车位
/**
* 车库停车
* 3车位
*/
@GetMapping("park")//停车方法
@ResponseBody
public String park() throws InterruptedException {
//取得信号量对象
RSemaphore park = redisson.getSemaphore("park");
//park.acquire();//获取一个信号,获取一个值,占一个车位,阻塞式获取
boolean b = park.tryAcquire();//尝试获取如果没有直接进行返回
return "ok";
}
@GetMapping("go")//开车走方法
@ResponseBody
public String go(){
//取得信号量对象
RSemaphore park = redisson.getSemaphore("park");
park.release();//释放车位
return "ok";
}
5.闭锁(CountDownLatch):基于redis的redisson的分布式闭锁,类似于放假锁门
/**
* 放假,锁门
* 需要五个班都走完,才能锁门
*/
@GetMapping("lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {
//获取闭锁对象
RCountDownLatch door = redisson.getCountDownLatch("door");
//设置需要关闭的数量
door.trySetCount(5);
door.await();//等待闭锁都完成
return "放假了";
}
@GetMapping("gogogo/{id}")
@ResponseBody
public String gogogo(@PathVariable("id")String id){
//获取闭锁对象
RCountDownLatch door = redisson.getCountDownLatch("door");
door.countDown();//计数减一
return id+"班人走完了...";
}