synchronized
關鍵字和各類 Lock
鎖,可是這種方式加的鎖只能保證在單項目或者說同一個jvm中起做用.可是在如今的分佈式環境下就不能很好的應對分佈式環境的加鎖需求,因此有了分佈式鎖通常過程分爲:加鎖,解鎖java
SET key value NX PX 2000
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
說明:通常設置分佈式鎖的時候,好比:金額操做會在多個地方,使用同一個key好比用戶帳號,這個時候若是沒獲取到鎖,確定不如直接返回報錯或異常或者直接結束,應該有個重試競爭機制redis
/** * @param jedis jedis 鏈接 * @param lockKey 傳入的鎖標識 * @param tryTimeoutMs 嘗試獲取鎖的時間 * @param lockTimeoutMS 鎖的超時時間 * @return 返回設置key對應的value值 */ public static String lock(Jedis jedis,String lockKey, long tryTimeoutMs, int lockTimeoutMS) { String retTip = null; String identifier = UUID.randomUUID().toString(); try { long end = System.currentTimeMillis() + tryTimeoutMs; while (System.currentTimeMillis() < end) { String result = jedis.set(lockKey, identifier, "NX", "PX", lockTimeoutMS); if ("OK".equals(result)) { retTip = identifier; break; } try { Thread.sleep(10); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } } catch (Exception e) { return "err"; } finally { // 異常釋放鏈接 if (jedis != null) { jedis.close(); } } return retTip; }
// 調用,循環屢次嘗試獲取鎖 public static void test(String[] args) { String key = "xxx";// key 標識 try { // 進行對應的操做 int cnt=0; while(true) { cnt++; if (cnt > 5) { throw new RuntimeException(); } String resTip = lock(jedisPool.getResource(),key, 6000, 5000); if (!org.springframework.util.StringUtils.isEmpty(resTip)) { if ("err".equals(resTip)) {//redis 出錯 throw new RuntimeException();// 異常退出 } // 獲取鎖以後的操做 releaseLock(key, resTip); break; } } }catch (Exception e) { e.printStackTrace(); } } private static final Long RELEASE_SUCCESS = 1L; /** * 釋放分佈式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 key * @param requestId 請求標識 value * @return 是否釋放成功 */ public static boolean releaseLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; }