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還是很有用的,等后面擴大了服務器的內存,在加入一下。