最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Redis分布式鎖的實現(xiàn)代碼

 更新時間:2018年05月07日 15:42:32   作者:liuyang0  
這篇文章主要介紹了Redis分布式鎖的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

概述

目前幾乎很多大型網(wǎng)站及應(yīng)用都是分布式部署的,分布式場景中的數(shù)據(jù)一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們“任何一個分布式系統(tǒng)都無法同時滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯性(Partition tolerance),最多只能同時滿足兩項。”所以,很多系統(tǒng)在設(shè)計之初就要對這三者做出取舍。在互聯(lián)網(wǎng)領(lǐng)域的絕大多數(shù)的場景中,都需要犧牲強一致性來換取系統(tǒng)的高可用性,系統(tǒng)往往只需要保證“最終一致性”,只要這個最終時間是在用戶可以接受的范圍內(nèi)即可。

在很多場景中,我們?yōu)榱吮WC數(shù)據(jù)的最終一致性,需要很多的技術(shù)方案來支持,比如分布式事務(wù)、分布式鎖等。

選用Redis實現(xiàn)分布式鎖原因

Redis有很高的性能

Redis命令對此支持較好,實現(xiàn)起來比較方便

在此就不介紹Redis的安裝了。

使用命令介紹

SETNX

SETNX key val
當且僅當key不存在時,set一個key為val的字符串,返回1;若key存在,則什么都不做,返回0。

expire

expire key timeout
為key設(shè)置一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。

delete

delete key
刪除key

在使用Redis實現(xiàn)分布式鎖的時候,主要就會使用到這三個命令。

實現(xiàn)

使用的是jedis來連接Redis。

實現(xiàn)思想

獲取鎖的時候,使用setnx加鎖,并使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

獲取鎖的時候還設(shè)置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執(zhí)行delete進行鎖釋放。
分布式鎖的核心代碼如下:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisException;
import java.util.List;
import java.util.UUID;
/**
 * Created by liuyang on 2017/4/20.
 */
public class DistributedLock {
 private final JedisPool jedisPool;
 public DistributedLock(JedisPool jedisPool) {
 this.jedisPool = jedisPool;
 }
 /**
 * 加鎖
 * @param locaName 鎖的key
 * @param acquireTimeout 獲取超時時間
 * @param timeout 鎖的超時時間
 * @return 鎖標識
 */
 public String lockWithTimeout(String locaName,
     long acquireTimeout, long timeout) {
 Jedis conn = null;
 String retIdentifier = null;
 try {
  // 獲取連接
  conn = jedisPool.getResource();
  // 隨機生成一個value
  String identifier = UUID.randomUUID().toString();
  // 鎖名,即key值
  String lockKey = "lock:" + locaName;
  // 超時時間,上鎖后超過此時間則自動釋放鎖
  int lockExpire = (int)(timeout / 1000);
  // 獲取鎖的超時時間,超過這個時間則放棄獲取鎖
  long end = System.currentTimeMillis() + acquireTimeout;
  while (System.currentTimeMillis() < end) {
  if (conn.setnx(lockKey, identifier) == 1) {
   conn.expire(lockKey, lockExpire);
   // 返回value值,用于釋放鎖時間確認
   retIdentifier = identifier;
   return retIdentifier;
  }
  // 返回-1代表key沒有設(shè)置超時時間,為key設(shè)置一個超時時間
  if (conn.ttl(lockKey) == -1) {
   conn.expire(lockKey, lockExpire);
  }
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
   Thread.currentThread().interrupt();
  }
  }
 } catch (JedisException e) {
  e.printStackTrace();
 } finally {
  if (conn != null) {
  conn.close();
  }
 }
 return retIdentifier;
 }
 /**
 * 釋放鎖
 * @param lockName 鎖的key
 * @param identifier 釋放鎖的標識
 * @return
 */
 public boolean releaseLock(String lockName, String identifier) {
 Jedis conn = null;
 String lockKey = "lock:" + lockName;
 boolean retFlag = false;
 try {
  conn = jedisPool.getResource();
  while (true) {
  // 監(jiān)視lock,準備開始事務(wù)
  conn.watch(lockKey);
  // 通過前面返回的value值判斷是不是該鎖,若是該鎖,則刪除,釋放鎖
  if (identifier.equals(conn.get(lockKey))) {
   Transaction transaction = conn.multi();
   transaction.del(lockKey);
   List<Object> results = transaction.exec();
   if (results == null) {
   continue;
   }
   retFlag = true;
  }
  conn.unwatch();
  break;
  }
 } catch (JedisException e) {
  e.printStackTrace();
 } finally {
  if (conn != null) {
  conn.close();
  }
 }
 return retFlag;
 }
}

測試

下面就用一個簡單的例子測試剛才實現(xiàn)的分布式鎖。
例子中使用50個線程模擬秒殺一個商品,使用--運算符來實現(xiàn)商品減少,從結(jié)果有序性就可以看出是否為加鎖狀態(tài)。

模擬秒殺服務(wù),在其中配置了jedis線程池,在初始化的時候傳給分布式鎖,供其使用。

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Created by liuyang on 2017/4/20.
 */
public class Service {
 private static JedisPool pool = null;
 static {
 JedisPoolConfig config = new JedisPoolConfig();
 // 設(shè)置最大連接數(shù)
 config.setMaxTotal(200);
 // 設(shè)置最大空閑數(shù)
 config.setMaxIdle(8);
 // 設(shè)置最大等待時間
 config.setMaxWaitMillis(1000 * 100);
 // 在borrow一個jedis實例時,是否需要驗證,若為true,則所有jedis實例均是可用的
 config.setTestOnBorrow(true);
 pool = new JedisPool(config, "127.0.0.1", 6379, 3000);
 }
 DistributedLock lock = new DistributedLock(pool);
 int n = 500;
 public void seckill() {
 // 返回鎖的value值,供釋放鎖時候進行判斷
 String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
 System.out.println(Thread.currentThread().getName() + "獲得了鎖");
 System.out.println(--n);
 lock.releaseLock("resource", indentifier);
 }
}
// 模擬線程進行秒殺服務(wù)

public class ThreadA extends Thread {
 private Service service;
 public ThreadA(Service service) {
 this.service = service;
 }
 @Override
 public void run() {
 service.seckill();
 }
}

public class Test {
 public static void main(String[] args) {
 Service service = new Service();
 for (int i = 0; i < 50; i++) {
  ThreadA threadA = new ThreadA(service);
  threadA.start();
 }
 }
}

結(jié)果如下,結(jié)果為有序的。

若注釋掉使用鎖的部分

public void seckill() {
 // 返回鎖的value值,供釋放鎖時候進行判斷
 //String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
 System.out.println(Thread.currentThread().getName() + "獲得了鎖");
 System.out.println(--n);
 //lock.releaseLock("resource", indentifier);
}

從結(jié)果可以看出,有一些是異步進行的。

在分布式環(huán)境中,對資源進行上鎖有時候是很重要的,比如搶購某一資源,這時候使用分布式鎖就可以很好地控制資源。
當然,在具體使用中,還需要考慮很多因素,比如超時時間的選取,獲取鎖時間的選取對并發(fā)量都有很大的影響,上述實現(xiàn)的分布式鎖也只是一種簡單的實現(xiàn),主要是一種思想。

下一次我會使用zookeeper實現(xiàn)分布式鎖,使用zookeeper的可靠性是要大于使用redis實現(xiàn)的分布式鎖的,但是相比而言,redis的性能更好。

上面的代碼可以在我的GitHub中進行查看。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 利用Redis統(tǒng)計網(wǎng)站在線活躍用戶的方法

    利用Redis統(tǒng)計網(wǎng)站在線活躍用戶的方法

    Redis支持對String類型的value進行基于二進制位的置位操作。通過將一個用戶的id對應(yīng)value上的一位,通過對活躍用戶對應(yīng)的位進行置位,就能夠用一個value記錄所有活躍用戶的信息。下面這篇文章主要介紹了利用Redis統(tǒng)計網(wǎng)站在線活躍用戶的方法,需要的朋友可以參考。
    2017-01-01
  • Redis入門教程詳解

    Redis入門教程詳解

    本文詳細介紹了Redis,文中主要講解了其基本數(shù)據(jù)結(jié)構(gòu)、高級數(shù)據(jù)結(jié)構(gòu)、高級特性、使用場景等,需要了解的朋友可以參考一下
    2021-08-08
  • 利用控制臺如何對Redis執(zhí)行增刪改查命令

    利用控制臺如何對Redis執(zhí)行增刪改查命令

    這篇文章主要給大家介紹了關(guān)于利用控制臺如何對Redis執(zhí)行增刪改查命令的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-08-08
  • Springboot/Springcloud項目集成redis進行存取的過程解析

    Springboot/Springcloud項目集成redis進行存取的過程解析

    大家都知道Redis支持五種數(shù)據(jù)類型:string(字符串),hash(哈希),list(列表),set(集合),zset(sorted set:有序集合),本文重點給大家介紹Springboot/Springcloud項目集成redis進行存取的過程,需要的朋友參考下吧
    2021-12-12
  • Redis源碼分析之set?和?sorted?set?使用

    Redis源碼分析之set?和?sorted?set?使用

    本文介紹了Redis?中的?set?和?sorted?set?使用源碼實現(xiàn)分析,Redis?的?Set?是?String?類型的無序集合,集合成員是唯一的,sorted?set有序集合和集合一樣也是?string?類型元素的集合,對Redis?set?和?sorted?set使用相關(guān)知識感興趣的朋友一起看看吧
    2022-03-03
  • Redis實現(xiàn)庫存扣減的示例代碼

    Redis實現(xiàn)庫存扣減的示例代碼

    在日常開發(fā)中有很多地方都有類似扣減庫存的操作,本文主要介紹了Redis實現(xiàn)庫存扣減的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2023-07-07
  • 詳解Redis如何多規(guī)則限流和防重復提交

    詳解Redis如何多規(guī)則限流和防重復提交

    市面上很多介紹redis如何實現(xiàn)限流的,但是大部分都有一個缺點,就是只能實現(xiàn)單一的限流,但是如果想一個接口兩種規(guī)則都需要滿足呢,使用本文就來介紹一下redis實現(xiàn)分布式多規(guī)則限流的方式吧
    2023-12-12
  • Linux中Redis安裝部署的操作步驟

    Linux中Redis安裝部署的操作步驟

    公司一直在使用redis集群,尋思著自己也部署一套練練手,下面這篇文章主要給大家介紹了關(guān)于Linux中Redis安裝部署的操作步驟,需要的朋友可以參考下
    2022-04-04
  • Redis如何在項目中合理使用經(jīng)驗分享

    Redis如何在項目中合理使用經(jīng)驗分享

    這篇文章主要給大家介紹了關(guān)于Redis如何在項目中合理使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • 深入理解redis中multi與pipeline

    深入理解redis中multi與pipeline

    pipeline 只是把多個redis指令一起發(fā)出去,redis并沒有保證這些指定的執(zhí)行是原子的;multi相當于一個redis的transaction的,保證整個操作的原子性,避免由于中途出錯而導致最后產(chǎn)生的數(shù)據(jù)不一致。本文詳細的介紹,感興趣的可以了解一下
    2021-06-06

最新評論

玉溪市| 常德市| 乌兰浩特市| 建宁县| 武城县| 安岳县| 大埔县| 潮安县| 永仁县| 巫山县| 永泰县| 镶黄旗| 丁青县| 张家界市| 邓州市| 松滋市| 嘉荫县| 日土县| 镇康县| 塔河县| 两当县| 上思县| 依安县| 习水县| 阿拉善盟| 乐都县| 平顶山市| 永清县| 黔江区| 饶河县| 上林县| 延边| 张家界市| 彰武县| 乐陵市| 剑川县| 寻甸| 五寨县| 遂昌县| 蒙阴县| 商水县|