標籤:get val mem exception client color 時間 分布式 錯誤
主要參考:
- http://blog.csdn.net/fjssharpsword/article/details/52250723#
- http://www.yiibai.com/redis/strings_getset.html
- https://redis.io/commands/expire
- https://www.baidu.com/link?url=kuDPE2uEXfjZO3qCggv2OaDGcd9_Mohb_S2Web1VHiY623cg4IJZRwqb0_tGyan7x0BJuV1I46dh-qGWCPEJsa&wd=&eqid=879de37e00008ea500000004583ef0f8
package com.deppon.spring;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.RejectedExecutionHandler;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import redis.clients.jedis.Jedis;/** * * @author ganxj * */public class BuildDistributedLockWithRedisDB { // 鎖名 private static final String lockName = "lock"; // 序列名 private static final String sequenceName = "sequence"; // 資料失效時間 private static final int expired = 1;// 1秒逾時 // 當前線程處理當次快取作業所需時間,(預估值) private static final int time = 10 * 1000; // setnx --- 若且唯若 key 不存在,將 key 的值設為 value ,並返回1;若給定的 key 已經存在,則 SETNX不做任何動作,並返回0。 // getSet -- 將給定 key 的值設為 value ,並返回 key 的舊值 (old value),當 key存在但不是字串類型時,返回一個錯誤,當key不存在時,返回nil。 // 上鎖 public static boolean acquireLock(Jedis jedis, String lock) { try { // 用於設定成功後的緩衝處理時間長度 long cacheProcessTime = System.currentTimeMillis() + time; // key為空白時,爭搶鎖 long isSetSuccessWhileKeyIsNil = jedis.setnx(lock, String.valueOf(cacheProcessTime)); // SETNX成功,則成功擷取一個鎖,並設定資料失效時間 if (isSetSuccessWhileKeyIsNil == 1) { jedis.expire(lock, expired); return true; } // key不為空白,SETNX失敗,說明鎖被其他用戶端保持,檢查其是否已經逾時 String lastLockTimeBySomeThread = jedis.get(lock); // 如果擷取key為空白,則重走空key時的加鎖流程 if (lastLockTimeBySomeThread == null) { return false; } // 擷取key不為空白,則判斷是否逾時,若未逾時,則迴圈重試 if (Long.valueOf(lastLockTimeBySomeThread) > System.currentTimeMillis()) { return false; } // 若逾時,則進行爭搶加鎖 String getOldIfSet = jedis.getSet(lock, String.valueOf(cacheProcessTime)); // 判斷加鎖是否成功 if (getOldIfSet != null && getOldIfSet.equals(lastLockTimeBySomeThread)) { return true; } // 若加鎖失敗,重頭再來 return false; } catch (Exception e) { e.printStackTrace(); } return false; } // 釋放鎖 public static void releaseLock(Jedis jedis, String lock) { try { String lastLockTimeBySomeThread = jedis.get(lock); if (lastLockTimeBySomeThread == null) { return; } // 避免刪除非自己擷取得到的鎖 if (System.currentTimeMillis() < Long.valueOf(lastLockTimeBySomeThread)) { jedis.del(lock); } } catch (Exception e) { e.printStackTrace(); } } @SuppressWarnings("resource") public static void main(String[] args) { // 任務數 int produceTaskMaxNumber = 100; // 初始化redis中的id序列 Jedis jedis = new Jedis(); jedis.set(sequenceName, String.valueOf(Long.valueOf(1))); // 初始化線程池 int corePoolSize = 20; int maximumPoolSize=20; long keepAliveTime =20; TimeUnit unit =TimeUnit.SECONDS; BlockingQueue<Runnable> workQueu = new ArrayBlockingQueue<Runnable>(30); RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueu, handler); // 建立任務 for (int i = 1; i <= produceTaskMaxNumber; i++) { try { threadPool.execute(new BuildDistributedLockWithRedisDB().new RedisLockTestTask()); } catch (Exception e) { e.printStackTrace(); } } } class RedisLockTestTask implements Runnable { @Override public void run() { Jedis jedis = new Jedis(); Boolean lockFlag = true; // 迴圈等待拿鎖 long startTime = System.currentTimeMillis(); while (lockFlag) { if (BuildDistributedLockWithRedisDB.acquireLock(jedis, lockName)) { // 獲得鎖了,開始執行商務邏輯 process(jedis, sequenceName); lockFlag = false; } } long endTime = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "線程設定的值:" + jedis.get(sequenceName) + " " + "共消耗時間長度:" + (endTime - startTime) + "ms"); // 釋放鎖 BuildDistributedLockWithRedisDB.releaseLock(jedis, lockName); } } void process(Jedis jedis,String sequenceName){ jedis.set(sequenceName, String.valueOf(Long.valueOf(jedis.get(sequenceName)) + 1)); }}
應用Redis實現分布式鎖