分布式锁
-
所有服务可以去一个公共的地方**“占坑“**,可以去数据库,也可以去redis,当占坑成功后,其他服务会判断有没有坑位,若已经被占了,则等待坑位,等待可以采取自旋的方式。
-
redis命令: set k v NX
-
redisTemplate相关的api setIfAbsent()
-
设置过期时间加锁成功 获取数据释放锁 [分布式下必须是Lua脚本删锁,不然会因为业务处理时间、网络延迟等等引起数据还没返回锁过期或者返回的过程中过期 然后把别人的锁删了]
-
**
redisson
定义: redis对于java实现的分布式框架
如何使用:
-
引入依赖
-
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.5</version> </dependency>
-
配置redisson:1.使用程序化配置 2.使用文本配置
-
这里采用程序化配置
@Bean(destroyMethod="shutdown")
public RedissonClient redisson() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
使用时直接注入即可
@Autowired
RedissonClient redissonClient;
可重入锁(Reetrant Lock)
- 假设有两个方法,分别为A、B,现在A方法里调用B方法,并且A B都想用锁,此时对A加可重入锁就代表拿到A的锁之后执行B相当于拿到了A、B的锁,可以不用等待就执行b方法
公平锁
- 假设有多个线程,其中一个线程抢到了锁,执行完之后释放锁,默认是其他线程去抢这个锁,谁抢到了谁执行。公平锁是在释放锁之后,其他线程会按照请求的时间去有顺序的抢占锁。
读写锁
写锁存在,读锁要等写锁释放,
读锁是一个排它锁(互斥锁),在并发写锁的情况下,写锁需要排队,读锁是一个共享锁。
写加读 读需要等写锁释放才可读
读加写 写需要等读释放才可以写
闭锁
public String lockDoor() throws InterruptedException {
RCountDownLatch door = redissonClient.getCountDownLatch("door");
// 设置这里有5个人
door.trySetCount(5);
//等待闭锁都完成
door.await();
return "5个人全部通过了...";
}
@ResponseBody
@GetMapping("/index/go/{id}")
public String go(@PathVariable("id") Long id) throws InterruptedException {
RCountDownLatch door = redissonClient.getCountDownLatch("door");
// 每访问一次相当于出去一个人
door.countDown();
return id + "走了";
}
信号量测试:
public String park() throws InterruptedException {
RSemaphore park = redissonClient.getSemaphore("park");
//阻塞方法,获取不到信号量会一直阻塞
park.acquire();
//非阻塞方法,过了一定时间获取不到信号量会返回false
boolean acquire = park.tryAcquire();
return "获取车位 =>" + acquire;
}
/**
* 尝试获取车位
*/
@ResponseBody
@GetMapping("/index/go/park")
public String goPark() {
RSemaphore park = redissonClient.getSemaphore("park");
park.release();
return "ok => 车位+1";
}