赞
踩
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson</artifactId>
- <version>3.13.6</version>
- </dependency>
-
- @Configuration
- public class RedissonConfig {
- @Bean
- public RedissonClient redissonClient(){
- Config config = new Config();
- config.useSingleServer().setAddress("redis://127.0.0.1:6379");//.setPassword("123456");
- return Redisson.create(config);
- }
- }
- @Autowired
- private RedissonClient redissonClient;
-
- @Test
- public void testLock(){
- RLock rLock = redissonClient.getLock("lock_stock");
- //阻塞式等待,过期时间30s
- rLock.lock();
- try{
- //执行业务
- }finally {
- //释放锁
- rLock.unlock();
- }
- }
如果负责存储分布式锁的Redission节点发生了宕机,并且锁没有被释放,就会出现死锁的现象。因此,为防止这种现象的产生,Redission有一个看门狗的机制,用来监控锁,若Redission实例未关闭,就会不断的延长锁的有效期,防止程序执行期间自动过期删除的问题。
Redisson加锁有以下两种情况:
(1)设置了过期时间
若设置了过期时间,会把设定的时间作为过期时间,然后使用Lua脚本获取到锁,未获取到锁的线程则会自旋重入,不停地尝试获取锁。
如果我们通过lease Time(rLock.lock(20, TimeUnit.SECONDS))的参数指定了加锁的时间,那么Redisson就不会再进行续期了,锁到达过期时间会自动释放锁,无需unlock手动解锁,如果出现锁的误删除情况时,Redisson会抛出异常。
(2)未设置过期时间
未设置过期时间的,Redisson加锁会有一个默认的过期时间为30s,线程获取到锁后,用了Lua来保证原子性,会开启一个定时任务,每隔10s看门狗会执行一次定时任务,若锁还在,重新将过期时间设置成30s。
- @Autowired
- private RedissonClient redissonClient;
-
- @Test
- public void testLock(){
- //获取锁
- RLock rLock = redissonClient.getLock("lock_stock");
- //加锁,锁的过期时间是10s,10s后锁自动释放
- rLock.lock(10, TimeUnit.SECONDS);
- try{
- //执行业务
- }finally {
- //释放锁,设置了锁的过期时间,不会手动调这个方法释放锁
- rLock.unlock();
- }
- }
公平锁保证了当多个Redisson客户端线程同时请求加锁时,会按照请求的顺序进行加锁,遵循先到先得的原则。
- @Autowired
- private RedissonClient redissonClient;
-
- @Test
- public void testLock5() {
- RLock fairLock = redissonClient.getFairLock("anyLock");
- try{
- fairLock.lock();
- }finally {
- //释放锁
- fairLock.unlock();
- }
- }
通过RedissonMultiLock对象可以将多个RLock锁关联为一个联锁,其中每个RLock对象实例都可以来自不同的Redisson实例。
- RLock lockA = redissonInstanceA.getLock("lockA");
- RLock lockB = redissonInstanceB.getLock("lockB");
- RLock lockC = redissonInstanceC.getLock("lockC");
-
- // 同时加锁:lockA, lockB, lockC
- RedissonMultiLock lock = new RedissonMultiLock(lockA, lockB, lockC);
-
- // 所有的都加锁成功才是成功
- lock.lock();
-
- // 释放锁
- lock.unlock();
可以将多个RLock关联成一个红锁,每个RLock对象实例可以来自于不同的Redisson实例,RedLock可以保证以下特性:
(1)容错性:只要大多数节点的redis实例能正常运行就可以加锁和释放锁。
(2)互斥性:只有一个客户端可以获取到锁,即使发生宕机,也不会造成死锁。
(3)一致性:降低了数据不一致的可能,但不能完全保证数据的一致性。
- RLock lockA = redissonInstanceA.getLock("lockA");
- RLock lockB = redissonInstanceB.getLock("lockB");
- RLock lockC = redissonInstanceC.getLock("lockC");
-
- // 同时加锁:lockA, lockB, lockC
- RedissonRedLock = new RedissonRedLock(lockA, lockB, lockC);
-
- // 大部分节点加锁成功就算成功
- lock.lock();
-
- // 释放锁
- lock.unlock();
Redisson提供了RCountDownLatch
接口,它是一个计数降低到0时触发的锁。它可以实现在多个线程都执行完才结束的效果,否则就会闭锁来等待。
- RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
-
- //设置数量为2
- latch.trySetCount(2);
-
- //await方法等待其他线程完成所有的trySetCount(2)就会结束闭锁
- latch.await();
-
- //在其他线程或其他JVM里
- RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
-
- //完成第1个countDown
- latch.countDown();
-
- // 在其他线程或其他JVM里
- RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
-
- //完成第2个countDown,闭锁完成
- latch.countDown();
Redisson的读写锁RReadWriteLock Java对象实现了ReadWriteLock接口。其中读锁和写锁都继承了RLock接口。
分布式的读写锁允许同时有多个读锁和一个写锁处在加锁的状态,也就是使用同一个RReadWriteLock来加写锁和读锁,读锁需要等待写锁释放锁之后才能够加锁成功。
- @Autowired
- private RedissonClient redissonClient;
-
- @Test
- public void testWriteLock() {
- //获取读写锁
- RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ReadWriteLock");
- //获取写锁
- RLock rLock = readWriteLock.writeLock();
- try{
- //加写锁,读等待
- rLock.lock();
- Thread.sleep(200000);
- //执行写业务
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- rLock.unlock();
- }
- }
- @Test
- public void testReadLock() {
- //获取读写锁
- RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ReadWriteLock");
- //获取读锁
- RLock rLock = readWriteLock.readLock();
- try{
- //加上读锁,若写锁没释放,等待
- rLock.lock();
- //处理读业务
- }finally {
- rLock.unlock();
- }
- }
Redisson的信号量可以看做是在Redis中保存了一个数字,可以实现原子性的加或减,比如取10件商品做库存,就可以把这个库存做成信号量,然后实现原子性加减。防止了库存出现负数的情况。
- @Autowired
- private RedissonClient redissonClient;
-
- @Test
- public void testReadLock() throws InterruptedException {
- //获得1个信号量
- RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
- //设置信号量的值
- boolean setPermits = semaphore.trySetPermits(1000);
- }
- @Test
- public void testReadLock6() throws InterruptedException {
- //获得到1个信号量
- RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
- //获取2个信号量 , 值会减去2 , 若获取不到,方法会阻塞
- semaphore.acquire(2);
-
- //尝试获取2个信号量 , 值会减去2 , 若获取不到,方法不会阻塞
- boolean tryAccquireSuccess = semaphore.tryAcquire(2);
- }
-
- @Test
- public void testReadLock7() throws InterruptedException {
- //获得到1个信号量
- RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
- //释放2个值,数量会加回去
- semaphore.release(2);
- }
除了上述的信号量,还提供了一个可过期的信号量,在RSemaphore对象的基础上,为每个信号增加了一个过期时间。每个信号可通过ID来进行区分,释放时也只能通过提交的ID才能释放。
- RPermitExpirableSemaphore semaphore = redisson.getPermitExpirableSemaphore("mySemaphore");
- String id = semaphore.acquire();
- // 获取1个信号,有效期只有1秒钟。
- String id = semaphore.acquire(1, TimeUnit.SECONDS);
-
- semaphore.release(id);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。