乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      redisLock redis分布式鎖

       觀審美2 2019-04-07

      redis-lock

      • redis setnx cmmand
      • java object condition queue 條件隊列
      • retrycount 帶有重試次數限制
      • object wait time 帶有超時時間的wait
      • delete lock 刪除遠程鎖
      • acquire lock 申請lock
      • release lock 釋放lock
      • demo 演示
      • 鎖的粒度問題,鎖分解、鎖分段
      • github https://github.com/Plen-wang/redis-lock

      redis setnx 命令

      redis setnx 命令特性

      當指定key不存在時才設置。也就是說,如果返回1說明你的命令被執(zhí)行成功了,redis服務器中的key是你之前設置的值。如果返回0,說明你設置的key在redis服務器里已經存在。

                  status = jedis.setnx(lockKey, redisIdentityKey);/**設置 lock key.*/
                  if (status > 0) {
                      expire = jedis.expire(lockKey, lockKeyExpireSecond);/**set  redis key expire time.*/
                  }

      如果設置成功了,才進行過期時間設置,防止你的retry lock重復設置這個過期時間,導致永遠不過期。

      java object condition queue 條件隊列

      這里有一個小竅門,可以盡可能的最大化cpu利用率又可以解決公平性問題。

      當你頻繁retry的時候,要么while(true)死循環(huán),然后加個Thread.sleep,或者CAS。前者存在一定線程上下文切換開銷(Thread.sleep是不會釋放出當前內置鎖),而CAS在不清楚遠程鎖被占用多久的情況會浪費很多CPU計算周期,有可能一個任務計算個十幾分鐘,CPU不可能空轉這么久。

      這里我嘗試使用condition queue條件隊列特性來實現(當然肯定還有其他更優(yōu)的方法)。

      if (isWait && retryCounts < RetryCount) {
                          retryCounts++;
                          synchronized (this) {//借助object condition queue 來提高CPU利用率
                              logger.info(String.
                                      format("t:%s,當前節(jié)點:%s,嘗試等待獲取鎖:%s", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                              this.wait(WaitLockTimeSecond); //未能獲取到lock,進行指定時間的wait再重試.
                          }
                      } else if (retryCounts == RetryCount) {
                          logger.info(String.
                                  format("t:%s,當前節(jié)點:%s,指定時間內獲取鎖失?。?s", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                          return false;
                      } else {
                          return false;//不需要等待,直接退出。
                      }

      使用條件隊列的好處就是,它雖然釋放出了CPU但是也不會持有當前synchronized,這樣就可以讓其他并發(fā)進來的線程也可以獲取到當前內置鎖,然后形成隊列。當wait時間到了被調度喚醒之后才會重新來申請synchronized鎖。
      簡單講就是不會再鎖上等待而是在隊列里等待。java object每一個對象都持有一個條件隊列,與當前內置鎖配合使用。

      retrycount 帶有重試次數限制

      等待遠程redis lock肯定是需要一定重試機制,但是這種重試是需要一定的限制。

          /**
           * 重試獲取鎖的次數,可以根據當前任務的執(zhí)行時間來設置。
           * 需要時間=RetryCount*(WaitLockTimeSecond/1000)
           */
          private static final int RetryCount = 10;

      這種等待是需要用戶指定的, if (isWait && retryCounts < RetryCount) ,當isWait為true才會進行重試。

      object wait time 帶有超時時間的wait

      object.wait(timeout),條件隊列中的方法wait是需要一個waittime。

          /**
           * 等待獲取鎖的時間,可以根據當前任務的執(zhí)行時間來設置。
           * 設置的太短,浪費CPU,設置的太長鎖就不太公平。
           */
          private static final long WaitLockTimeSecond = 2000;

      默認2000毫秒。

      this.wait(WaitLockTimeSecond); //未能獲取到lock,進行指定時間的wait再重試.

      注意:this.wait雖然會blocking住,但是這里的內置鎖是會立即釋放出來的。所以,有時候我們可以借助這種特性來優(yōu)化特殊場景。

      delete lock 刪除遠程鎖

      釋放redis lock比較簡單,直接del key就好了

      long status = jedis.del(lockKey);
              if (status > 0) {
                  logger.info(String.
                          format("t:%s,當前節(jié)點:%s,釋放鎖:%s 成功。", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                  return true;
              }

      一旦delete 之后,首先wait喚醒的線程將會獲得鎖。

      acquire lock 申請lock

      /**
           * 帶超時時間的redis lock.
           *
           * @param lockKeyExpireSecond 鎖key在redis中的過去時間
           * @param lockKey             lock key
           * @param isWait              當獲取不到鎖時是否需要等待
           * @throws Exception lockKey is empty throw exception.
           */
          public Boolean acquireLockWithTimeout(int lockKeyExpireSecond, String lockKey, Boolean isWait) throws Exception {
              if (StringUtils.isEmpty(lockKey)) throw new Exception("lockKey is empty.");
      
              int retryCounts = 0;
              while (true) {
                  Long status, expire = 0L;
                  status = jedis.setnx(lockKey, redisIdentityKey);/**設置 lock key.*/
                  if (status > 0) {
                      expire = jedis.expire(lockKey, lockKeyExpireSecond);/**set  redis key expire time.*/
                  }
                  if (status > 0 && expire > 0) {
                      logger.info(String.
                              format("t:%s,當前節(jié)點:%s,獲取到鎖:%s", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                      return true;/**獲取到lock*/
                  }
      
                  try {
                      if (isWait && retryCounts < RetryCount) {
                          retryCounts++;
                          synchronized (this) {//借助object condition queue 來提高CPU利用率
                              logger.info(String.
                                      format("t:%s,當前節(jié)點:%s,嘗試等待獲取鎖:%s", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                              this.wait(WaitLockTimeSecond); //未能獲取到lock,進行指定時間的wait再重試.
                          }
                      } else if (retryCounts == RetryCount) {
                          logger.info(String.
                                  format("t:%s,當前節(jié)點:%s,指定時間內獲取鎖失?。?s", Thread.currentThread().getId(), getRedisIdentityKey(), lockKey));
                          return false;
                      } else {
                          return false;//不需要等待,直接退出。
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      
      
      ## release lock 釋放lock
      /**
           * 釋放redis lock。
           *
           * @param lockKey lock key
           * @throws Exception lockKey is empty throw exception.
           */
          public Boolean releaseLockWithTimeout(String lockKey) throws Exception {
              if (StringUtils.isEmpty(lockKey)) throw new Exception("lockKey is empty.");
      
              long status = jedis.del(lockKey);
              if (status > 0) {
                  logger.info(String.format("當前節(jié)點:%s,釋放鎖:%s 成功。", getRedisIdentityKey(), lockKey));
                  return true;
              }
              logger.info(String.format("當前節(jié)點:%s,釋放鎖:%s 失敗。", getRedisIdentityKey(), lockKey));
              return false;
          }

      demo 演示

      2017-06-18 13:57:43.867 INFO 1444 --- [nio-8080-exec-1] c.plen.opensource.implement.RedisLocker : t:23,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,獲取到鎖:product:10100101:shopping
      2017-06-18 13:57:47.062 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:49.063 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:51.064 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:53.066 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:55.068 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:57.069 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:57:59.070 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:01.071 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:03.072 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:05.073 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:07.074 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,指定時間內獲取鎖失?。簆roduct:10100101:shopping
      2017-06-18 13:58:23.768 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:25.769 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:27.770 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:29.772 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:31.773 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:33.774 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:35.774 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,獲取到鎖:product:10100101:shopping

      thread 23 優(yōu)先獲取到對商品ID 10100101 進行修改,所以先鎖住當前商品。

      t:23,當前節(jié)點:843d3ec0-9c22-4d8a-bcaa-745dba35b8a4,獲取到鎖:product:10100101:shopping

      緊接著,thread 25也來對當前商品 10100101進行修改,所以在嘗試獲取鎖。

      2017-06-18 13:50:11.021 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:13.023 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:15.026 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:17.028 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:19.030 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:21.031 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:23.035 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:25.037 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:27.041 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:29.042 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:50:35.289 INFO 4616 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:946b7250-29f3-459b-8320-62d31e6f1fc4,指定時間內獲取鎖失敗:product:10100101:shopping

      在進行了retry10次(2000毫秒,2秒)之后,獲取失敗,直接返回,等待下次任務調度開始。

      2017-06-18 13:58:07.074 INFO 1444 --- [nio-8080-exec-3] c.plen.opensource.implement.RedisLocker : t:25,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,指定時間內獲取鎖失?。簆roduct:10100101:shopping
      2017-06-18 13:58:23.768 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:25.769 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:27.770 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:29.772 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:31.773 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:33.774 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,嘗試等待獲取鎖:product:10100101:shopping
      2017-06-18 13:58:35.774 INFO 1444 --- [nio-8080-exec-6] c.plen.opensource.implement.RedisLocker : t:28,當前節(jié)點:5f81f482-295a-4394-b8cb-d7282e51dd6e,獲取到鎖:product:10100101:shopping

      thread 28 發(fā)起對商品 10100101 進行修改,retry6次之后獲取到lock。

      鎖的粒度問題,鎖分解、鎖分段

      這里的例子比較簡單。如果在并發(fā)比較大的情況下是需要結合鎖分解、鎖分段來進行優(yōu)化的。
      修改商品,沒有必要鎖住整個商品庫,只需要鎖住你需要修改的指定ID的商品。也可以借鑒鎖分段思路,將數據按照一定維度進行劃分,然后加上不同維度的鎖,可以提升CPU性能??梢愿鶕唐穋atagory來設計段鎖或者batch來設計段鎖。

      github

      源碼已提交gihub,代碼如有不對請多指教。
      github地址:https://github.com/Plen-wang/redis-lock

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多