谷粒商城Redisson分布式锁(二十四)
159、缓存-分布式锁-Redisson简介&整合 - 166、缓存-分布式锁-缓存一致性解决
官网说明:https://github.com/redisson/redisson
反正也很详细,有说明,也有配置的用法,感兴趣的可以具体看一下。底层也是用到lua脚本
/** * 简单请求 * @return */ @ResponseBody @GetMapping("/hello") public String hello() { RLock rLock = redisson.getLock("my-lock"); //1.锁的自动续期,如果业务超长,运行期间会自动给锁续上新的30s。不用担心业务时间长,锁自动被删掉 //2.加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s以后自动删除。 //rLock.lock(); rLock.lock(30, TimeUnit.SECONDS); //10秒自动解锁,自动解锁时间一定要大于业务的执行时间 //问题:rLock.lock(10, TimeUnit.SECONDS); 在锁时间到了以后,不会自动续期 //1.如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间。 //2.如果我们未指定锁的超时时间,就使用30*1000的LockWatchTimeout看门狗的默认时间; // 只要占锁成功,就会启动一个定时任务,每隔10s都会自动续期 //建议; rLock.lock(30, TimeUnit.SECONDS); 省掉了续期的时间 try { System.out.println("加锁成功,执行业务"+Thread.currentThread().getId()); Thread.sleep(30000); }catch(Exception e){ }finally { System.out.println("释放锁"+Thread.currentThread().getId()); rLock.unlock(); }
//保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁)。读锁是一个共享锁 //写锁没释放读就必须等待 //读 + 读: 相当于无锁,并发读,只会在redis中记录好,所有当前的读锁。他们都会同时加锁成功 //写 + 读: 等待写锁释放 //写 + 写: 阻塞方式 //读 + 写: 有读锁。写也需要等待 //只要有写的存在,都必须等待。 @GetMapping("/write") @ResponseBody public String writeValue(){ RReadWriteLock lock = redisson.getReadWriteLock("rw-lock"); String s = ""; RLock rLock = lock.writeLock(); try { rLock.lock(); s = UUID.randomUUID().toString(); redisTemplate.opsForValue().set("writeValue",s); } catch (Exception e) { e.printStackTrace(); }finally { rLock.unlock(); } return s; } @GetMapping("/read") @ResponseBody public String read(){ RReadWriteLock lock = redisson.getReadWriteLock("rw-lock"); String s = ""; RLock rLock = lock.readLock(); try { rLock.lock(); Thread.sleep(30000); s = redisTemplate.opsForValue().get("writeValue"); } catch (InterruptedException e) { e.printStackTrace(); }finally { rLock.unlock(); } return s; }
读写锁(ReadWriteLock)
基于Redis的Redisson分布式可重入读写锁RReadWriteLock
Java对象实现了java.util.concurrent.locks.ReadWriteLock
接口。其中读锁和写锁都继承了RLock接口。
分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock"); // 最常见的使用方法 rwlock.readLock().lock(); // 或 rwlock.writeLock().lock();
大家都知道,如果负责储存这个分布式锁的Redis节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。
另外Redisson还通过加锁的方法提供了leaseTime
的参数来指定加锁的时间。超过这个时间后锁便自动解开了。
// 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();
闭锁(CountDownLatch)
基于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();
@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") Long id){ RCountDownLatch door = redisson.getCountDownLatch("door"); door.countDown(); return id+"班的人都走了"; }
信号量(Semaphore)
基于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();
加上Redisson锁
//Redisson加上分布式锁 public Map<String, List<Catalog2Vo>> getCatalogJsonFromDbRedissonLock() { RLock lock = redisson.getLock("catalogSon-lock"); lock.lock(); log.info("分布式加锁成功"); Map<String, List<Catalog2Vo>> dataFromDb; try{ dataFromDb = getDataFromDb(); }finally{ lock.unlock(); log.info("分布式解锁成功"); } return dataFromDb; }
解决方案:
canal还是很有用的,等后面扩大了服务器的内存,在加入一下。