<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 面試官:基于Redis怎么實現分布式鎖? ## 一、錯誤方案:只使用setnx(key, value, expires) 1. 不同的服務器啟動時間是不一致的; 2. key的過期時間設置太短,會有可能導致任務重復執行; 3. key的過期時間設置太長,則有可能錯過下次任務執行周期; 因此,在這種場景下,保持服務器時間基本同步的情況下,設置小于周期,且足夠大于服務器誤差時間的周期,以保證該任務只能執行一次。 ![](https://img.kancloud.cn/cd/c1/cdc1e202b91c756cf5ddcf0176f84e28_970x248.png) 但是`缺點`也非常明顯: 1. 服務器時間最早的機器會一直獲得任務的執行權; 2. 基于服務器時間基本能夠同步的條件; 3. key過期時長設置無法形成較好的標準。 > 無論是大周期任務,還是高并發場景下,都不應這樣直接使用。 ## 二、基于客戶端標識的本地時間差比較 Redis中存儲的除了鎖key,還有本地隨機字符串+過期時間差。其源碼如下: ``` //保存客戶端標識 private static final ThreadLocal<String> LOCAL = new ThreadLocal<String>(); /** * * @param jedis * @param lockKey 鎖key * @param expires 過期時間 一般為 System.currentTimeMillis()+ 過期時間 * @return */ public static boolean getDistributedLock(Jedis jedis, String lockKey, long expires) { //客戶端標識 在釋放鎖時 確保由設置鎖的客戶端來釋放自己的鎖 String uuid = UUID.randomUUID().toString(); LOCAL.set(uuid); String expiresStr = uuid+"#"+expires; // 如果當前鎖不存在,返回加鎖成功 if (jedis.setnx(lockKey, expiresStr) == 1) { return true; } // 如果鎖存在,獲取鎖的過期時間 String currentValue = jedis.get(lockKey); String currentValueStr = null==currentValue?null:currentValue.split("#")[1]; // 判斷當前鎖是否過期 if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { // 鎖已過期,獲取上一個鎖的過期時間,并設置現在鎖的過期時間 此處多個客戶端會覆蓋鎖的過期時間 String oldValue = jedis.getSet(lockKey,expiresStr); String oldValueStr = null ==oldValue?null:oldValue.split("#")[1]; // 考慮多線程并發的情況,只有一個線程的設置值和當前值相同,它才有權利加鎖 if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { //由于上面會覆蓋鎖的過期時間 此處讓獲取鎖的客戶端 重新設置為自己的過期時間 jedis.set(lockKey,expiresStr); return true; } } // 其他情況,一律返回加鎖失敗 return false; } /** * * @param jedis * @param lockKey 鎖key * @param value 過期時間 一般為 System.currentTimeMillis()+ 過期時間 * @return */ public static boolean releaseDistributedLock(Jedis jedis, String lockKey, long value) { String uuid = LOCAL.get(); String valueStr = uuid+"#"+value; //根據uuid 這個標識 讓客戶端 去釋放自己的鎖 不能釋放別人的鎖 if(valueStr.equals(jedis.get(lockKey))){ jedis.del(lockKey); return true; } return false; } ``` ## 三、參考資料 1. [基于Redis的分布式鎖 基于setnx的正確實現方式](https://blog.csdn.net/wudidewu/article/details/79817125)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看