<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          redisTemplate分布式鎖演變、redission分布式鎖實現(xiàn)!

          共 13400字,需瀏覽 27分鐘

           ·

          2021-07-18 16:19


          來源:blog.csdn.net/zhangkaixuan456
          /article/details/110679617
          分布式鎖的演進

          基本原理

          我們可以同時去一個地方“占坑”,如果占到,就執(zhí)行邏輯。否則就必須等待,直到釋放鎖?!罢伎印笨梢匀edis,可以去數(shù)據(jù)庫,可以去任何大家都能訪問的地方。等待可以自旋的方式。

          階段一

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  //階段一
                  Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""111");
                  //獲取到鎖,執(zhí)行業(yè)務
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      //刪除鎖,如果在此之前報錯或宕機會造成死鎖
                      stringRedisTemplate.delete("lock");
                      return categoriesDb;
                  }else {
                      //沒獲取到鎖,等待100ms重試
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }
           
          public Map<String, List<Catalog2Vo>> getCategoryMap() {
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                  String catalogJson = ops.get("catalogJson");
                  if (StringUtils.isEmpty(catalogJson)) {
                      System.out.println("緩存不命中,準備查詢數(shù)據(jù)庫。。。");
                      Map<String, List<Catalog2Vo>> categoriesDb= getCategoriesDb();
                      String toJSONString = JSON.toJSONString(categoriesDb);
                      ops.set("catalogJson", toJSONString);
                      return categoriesDb;
                  }
                  System.out.println("緩存命中。。。。");
                  Map<String, List<Catalog2Vo>> listMap = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {});
                  return listMap;
              }
          問題: setnx占好了位,業(yè)務代碼異?;蛘叱绦蛟陧撁孢^程中宕機。沒有執(zhí)行刪除鎖邏輯,這就造成了死鎖
          解決: 設(shè)置鎖的自動過期,即使沒有刪除,會自動刪除

          階段二

           public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""111");
                  if (lock) {
                      //設(shè)置過期時間
                      stringRedisTemplate.expire("lock"30, TimeUnit.SECONDS);
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      stringRedisTemplate.delete("lock");
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }
          問題: setnx設(shè)置好,正要去設(shè)置過期時間,宕機。又死鎖了。
          解決: 設(shè)置過期時間和占位必須是原子的。redis支持使用setnx ex命令

          階段三

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
              //加鎖的同時設(shè)置過期時間,二者是原子性操作
              Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock""1111",5, TimeUnit.SECONDS);
              if (lock) {
                  Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                  //模擬超長的業(yè)務執(zhí)行時間
                  try {
                      Thread.sleep(6000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  stringRedisTemplate.delete("lock");
                  return categoriesDb;
              }else {
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  return getCatalogJsonDbWithRedisLock();
              }
          }
          問題: 刪除鎖直接刪除???如果由于業(yè)務時間很長,鎖自己過期了,我們直接刪除,有可能把別人正在持有的鎖刪除了。
          解決: 占鎖的時候,值指定為uuid,每個人匹配是自己的鎖才刪除。

          階段四

          public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  String uuid = UUID.randomUUID().toString();
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                //為當前鎖設(shè)置唯一的uuid,只有當uuid相同時才會進行刪除鎖的操作
                  Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      String lockValue = ops.get("lock");
                      if (lockValue.equals(uuid)) {
                          try {
                              Thread.sleep(6000);
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                          stringRedisTemplate.delete("lock");
                      }
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }
          問題: 如果正好判斷是當前值,正要刪除鎖的時候,鎖已經(jīng)過期,別人已經(jīng)設(shè)置到了新的值。那么我們刪除的是別人的鎖
          解決: 刪除鎖必須保證原子性。使用redis+Lua腳本完成

          階段五-最終形態(tài)

           public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() {
                  String uuid = UUID.randomUUID().toString();
                  ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                  Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS);
                  if (lock) {
                      Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap();
                      String lockValue = ops.get("lock");
                      String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                              "    return redis.call(\"del\",KEYS[1])\n" +
                              "else\n" +
                              "    return 0\n" +
                              "end";
                      stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue);
                      return categoriesDb;
                  }else {
                      try {
                          Thread.sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      return getCatalogJsonDbWithRedisLock();
                  }
              }
          保證加鎖【占位+過期時間】和刪除鎖【判斷+刪除】的原子性。更難的事情,鎖的自動續(xù)期

          Redisson

          Redisson是一個在Redis的基礎(chǔ)上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務。
          其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)
          Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關(guān)注分離(Separation of Concern),從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務邏輯上。
          更多請參考官方文檔:
          https://github.com/redisson/redisson/wiki

          END


          順便給大家推薦一個GitHub項目,這個 GitHub 整理了上千本常用技術(shù)PDF,絕大部分核心的技術(shù)書籍都可以在這里找到,

          GitHub地址:https://github.com/javadevbooks/books

          Gitee地址:https://gitee.com/javadevbooks/books

          電子書已經(jīng)更新好了,你們需要的可以自行下載了,記得點一個star,持續(xù)更新中..



          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天撸一撸视频 | 中文字幕亚洲在线播放 | 521大香蕉网站。大香蕉综合伊人 91成人视频一区二区三区在线观看 | 蜜芽亚洲av无码精品色午夜 | 国产熟妇毛多 久久久久一区 |