redis分布式鎖如何實現原理

redis分布式鎖如何實現原理

分布式鎖,是控制分布式系統之間同步訪問共享資源的一種方式。

在分布式系統中,常常需要協調他們的動作。如果不同的系統或是同一個系統的不同主機之間共享了一個或一組資源,那么訪問這些資源的時候,往往需要互斥來防止彼此干擾來保證一致性,在這種情況下,便需要使用到分布式鎖。

使用setnx、getset、expire、del這4個redis命令實現 ? (推薦學習:Redis視頻教程

setnx 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。 命令格式:SETNX key value;使用:只在鍵 key 不存在的情況下,將鍵 key 的值設置為 value 。若鍵 key 已經存在, 則 SETNX 命令不做任何動作。返回值:命令在設置成功時返回 1 ,設置失敗時返回 0 。

getset 命令格式:GETSET key value,將鍵 key 的值設為 value ,并返回鍵 key 在被設置之前的舊的value。返回值:如果鍵 key 沒有舊值, 也即是說, 鍵 key 在被設置之前并不存在, 那么命令返回 nil 。當鍵 key 存在但不是字符串類型時,命令返回一個錯誤。

expire 命令格式:EXPIRE key seconds,使用:為給定 key 設置生存時間,當 key 過期時(生存時間為 0 ),它會被自動刪除。返回值:設置成功返回 1 。 當 key 不存在或者不能為 key 設置生存時間時(比如在低于 2.1.3 版本的 redis 中你嘗試更新 key 的生存時間),返回 0 。

del 命令格式:DEL key [key …],使用:刪除給定的一個或多個 key ,不存在的 key 會被忽略。返回值:被刪除 key 的數量。

Redis實現分布式鎖的原理:

1.通過setnx(lock_timeout)實現,如果設置了鎖返回1, 已經有值沒有設置成功返回0

2.死鎖問題:通過實踐來判斷是否過期,如果已經過期,獲取到過期時間get(lockKey),然后getset(lock_timeout)判斷是否和get相同,相同則證明已經加鎖成功,因為可能導致線程同時執行getset(lock_timeout)方法,這可能導致多線程都只需getset后,對于判斷加鎖成功的線程, 再加expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS)過期時間,防止多個線程同時疊加時間,導致鎖時效時間翻倍

redis分布式鎖如何實現原理代碼:

/** ?*?@author?yaoxin ?*?@date?2018/8/13下午5:04 ?*/ public?class?RedisLockTest?{ ? ????public?static?final?String?url?=?"jdbc:mysql://127.0.0.1:3306/ly?characterEncoding=UTF-8"; ????public?static?final?String?name?=?"com.mysql.jdbc.Driver"; ????public?static?final?String?user?=?"root"; ????public?static?final?String?password?=?""; ? ????public?static?void?main(String[]?args)?{ ? ????????Integer?count?=?50; ????????while?(count?&gt;?0)?{ ????????????count--; ????????????new?Thread(new?Runnable()?{ ????????????????@Override ????????????????public?void?run()?{ ????????????????????Jedis?jedis?=?new?Jedis("127.0.0.1",?6379); ????????????????????jedis.auth("1234"); ????????????????????String?lock?=?lock(jedis); ????????????????????if?(lock?!=?null)?{ ????????????????????????Statement?statement?=?null; ????????????????????????Connection?conn?=?null; ????????????????????????ResultSet?resultSet?=?null; ????????????????????????try?{ ????????????????????????????Class.forName(name);//?指定連接類型 ????????????????????????????conn?=?DriverManager.getConnection(url,?user,?password);//?獲取連接 ????????????????????????????statement?=?conn.createStatement();//?準備執行語句 ????????????????????????????String?querySql?=?"SELECT?id,name,count?FROM?production?WHERE?id=2"; ????????????????????????????resultSet?=?statement.executeQuery(querySql); ????????????????????????????int?count?=?0; ????????????????????????????while?(resultSet.next())?{ ????????????????????????????????System.out.println(Thread.currentThread().getName()?+?"搶到了鎖?id:?"?+?resultSet.getString("id") ????????????????????????????????????????+?"?name:?"?+?resultSet.getString("name") ????????????????????????????????????????+?"?count:?"?+?resultSet.getString("count")); ????????????????????????????????count?=?Integer.valueOf(resultSet.getString("count")); ????????????????????????????} ????????????????????????????String?updateSql?=?"UPDATE?production?SET?count="?+?(count?-?1) ????????????????????????????????????+?"?WHERE?id=2"; ????????????????????????????int?rows?=?statement.executeUpdate(updateSql); ????????????????????????????if?(rows?&gt;?0)?{ ????????????????????????????????System.out.println("更新成功"?+?Thread.currentThread().getName()?+?"??庫存剩余:"?+?(count?-?1)); ????????????????????????????????System.out.println(Thread.currentThread().getName()?+?"?===?&gt;?&gt;開始解鎖"); ????????????????????????????????boolean?unlock?=?unlock(jedis,?lock); ????????????????????????????????if?(unlock) ????????????????????????????????????System.out.println(Thread.currentThread().getName()?+?"?===?&gt;?&gt;解鎖成功"); ????????????????????????????}?else?{ ????????????????????????????????System.out.println("更新失敗"?+?Thread.currentThread().getName()); ????????????????????????????} ????????????????????????}?catch?(Exception?e)?{ ????????????????????????????e.printStackTrace(); ????????????????????????}?finally?{ ????????????????????????????try?{ ????????????????????????????????if?(conn?!=?null) ????????????????????????????????????conn.close(); ????????????????????????????????if?(statement?!=?null) ????????????????????????????????????statement.close(); ????????????????????????????????if?(resultSet?!=?null) ????????????????????????????????????resultSet.close(); ????????????????????????????}?catch?(Exception?e)?{ ????????????????????????????????e.printStackTrace(); ????????????????????????????} ????????????????????????} ????????????????????} ????????????????} ????????????},?"線程"?+?count).start(); ????????} ????} ? ????public?static?String?lock(Jedis?jedis)?{ ????????try?{ ????????????while?(true)?{ ????????????????String?lockTime?=?Long.valueOf(jedis.time().get(0))?+?5?+?""; ????????????????if?(jedis.setnx("lock",?lockTime)?==?1)?{ ????????????????????jedis.expire("lock",?5); ????????????????????return?lockTime; ????????????????} ????????????????String?lock?=?jedis.get("lock"); ????????????????if?(!StringUtils.isEmpty(lock)?&amp;&amp;?Long.valueOf(lock)?<p><strong>運行結果如下圖:</strong></p><p><img src="https://img.php.cn/upload/image/559/447/230/1574907188872312.jpg" title="1574907188872312.jpg" alt="redis-9.jpg"></p><p>更多Redis相關技術文章,請訪問<a href="https://www.php.cn/course/list/54.html" target="_self">Redis視頻教程</a>欄目進行學習!</p>

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享