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

Java使用Redisson分布式鎖實(shí)現(xiàn)原理

 更新時(shí)間:2018年10月23日 09:13:16   作者:不要亂摸  
Redisson分布式鎖 之前的基于注解的鎖有一種鎖是基本redis的分布式鎖,這篇文章主要介紹了Java使用Redisson分布式鎖實(shí)現(xiàn)原理,非常具有實(shí)用價(jià)值,需要的朋友可以參考下

1. 基本用法

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson</artifactId>
  <version>3.8.2</version>
</dependency>
Config config = new Config();
config.useClusterServers()
  .setScanInterval(2000) // cluster state scan interval in milliseconds
  .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
  .addNodeAddress("redis://127.0.0.1:7002");

RedissonClient redisson = Redisson.create(config);

RLock lock = redisson.getLock("anyLock");

lock.lock();

try {
  ...
} finally {
  lock.unlock();
}

針對(duì)上面這段代碼,重點(diǎn)看一下Redisson是如何基于Redis實(shí)現(xiàn)分布式鎖的

Redisson中提供的加鎖的方法有很多,但大致類似,此處只看lock()方法

更多請(qǐng)參見(jiàn)https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers

2. 加鎖

可以看到,調(diào)用getLock()方法后實(shí)際返回一個(gè)RedissonLock對(duì)象,在RedissonLock對(duì)象的lock()方法主要調(diào)用tryAcquire()方法

由于leaseTime == -1,于是走tryLockInnerAsync()方法,這個(gè)方法才是關(guān)鍵

首先,看一下evalWriteAsync方法的定義

復(fù)制代碼 代碼如下:
<T, R> RFuture<R> evalWriteAsync(String key, Codec codec, RedisCommand<T> evalCommandType, String script, List<Object> keys, Object ... params);

最后兩個(gè)參數(shù)分別是keys和params

實(shí)際調(diào)用是這樣的:

單獨(dú)將調(diào)用的那一段摘出來(lái)看

commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
         "if (redis.call('exists', KEYS[1]) == 0) then " +
           "redis.call('hset', KEYS[1], ARGV[2], 1); " +
           "redis.call('pexpire', KEYS[1], ARGV[1]); " +
           "return nil; " +
         "end; " +
         "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
           "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
           "redis.call('pexpire', KEYS[1], ARGV[1]); " +
           "return nil; " +
         "end; " +
         "return redis.call('pttl', KEYS[1]);",
          Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));

結(jié)合上面的參數(shù)聲明,我們可以知道,這里KEYS[1]就是getName(),ARGV[2]是getLockName(threadId)

假設(shè)前面獲取鎖時(shí)傳的name是“abc”,假設(shè)調(diào)用的線程ID是Thread-1,假設(shè)成員變量UUID類型的id是6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c

那么KEYS[1]=abc,ARGV[2]=6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c:Thread-1

因此,這段腳本的意思是

  1、判斷有沒(méi)有一個(gè)叫“abc”的key

  2、如果沒(méi)有,則在其下設(shè)置一個(gè)字段為“6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c:Thread-1”,值為“1”的鍵值對(duì) ,并設(shè)置它的過(guò)期時(shí)間

  3、如果存在,則進(jìn)一步判斷“6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c:Thread-1”是否存在,若存在,則其值加1,并重新設(shè)置過(guò)期時(shí)間

  4、返回“abc”的生存時(shí)間(毫秒)

這里用的數(shù)據(jù)結(jié)構(gòu)是hash,hash的結(jié)構(gòu)是: key 字段1 值1 字段2 值2 。。。

用在鎖這個(gè)場(chǎng)景下,key就表示鎖的名稱,也可以理解為臨界資源,字段就表示當(dāng)前獲得鎖的線程

所有競(jìng)爭(zhēng)這把鎖的線程都要判斷在這個(gè)key下有沒(méi)有自己線程的字段,如果沒(méi)有則不能獲得鎖,如果有,則相當(dāng)于重入,字段值加1(次數(shù))

3. 解鎖

protected RFuture<Boolean> unlockInnerAsync(long threadId) {
  return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
      "if (redis.call('exists', KEYS[1]) == 0) then " +
        "redis.call('publish', KEYS[2], ARGV[1]); " +
        "return 1; " +
      "end;" +
      "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
        "return nil;" +
      "end; " +
      "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
      "if (counter > 0) then " +
        "redis.call('pexpire', KEYS[1], ARGV[2]); " +
        "return 0; " +
      "else " +
        "redis.call('del', KEYS[1]); " +
        "redis.call('publish', KEYS[2], ARGV[1]); " +
        "return 1; "+
      "end; " +
      "return nil;",
      Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));

}

我們還是假設(shè)name=abc,假設(shè)線程ID是Thread-1

同理,我們可以知道

KEYS[1]是getName(),即KEYS[1]=abc

KEYS[2]是getChannelName(),即KEYS[2]=redisson_lock__channel:{abc}

ARGV[1]是LockPubSub.unlockMessage,即ARGV[1]=0

ARGV[2]是生存時(shí)間

ARGV[3]是getLockName(threadId),即ARGV[3]=6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c:Thread-1

因此,上面腳本的意思是:

  1、判斷是否存在一個(gè)叫“abc”的key

  2、如果不存在,向Channel中廣播一條消息,廣播的內(nèi)容是0,并返回1

  3、如果存在,進(jìn)一步判斷字段6f0829ed-bfd3-4e6f-bba3-6f3d66cd176c:Thread-1是否存在

  4、若字段不存在,返回空,若字段存在,則字段值減1

  5、若減完以后,字段值仍大于0,則返回0

  6、減完后,若字段值小于或等于0,則廣播一條消息,廣播內(nèi)容是0,并返回1;

可以猜測(cè),廣播0表示資源可用,即通知那些等待獲取鎖的線程現(xiàn)在可以獲得鎖了

4. 等待

以上是正常情況下獲取到鎖的情況,那么當(dāng)無(wú)法立即獲取到鎖的時(shí)候怎么辦呢?

再回到前面獲取鎖的位置

@Override
public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
  long threadId = Thread.currentThread().getId();
  Long ttl = tryAcquire(leaseTime, unit, threadId);
  // lock acquired
  if (ttl == null) {
    return;
  }

  //  訂閱
  RFuture<RedissonLockEntry> future = subscribe(threadId);
  commandExecutor.syncSubscription(future);

  try {
    while (true) {
      ttl = tryAcquire(leaseTime, unit, threadId);
      // lock acquired
      if (ttl == null) {
        break;
      }

      // waiting for message
      if (ttl >= 0) {
        getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
      } else {
        getEntry(threadId).getLatch().acquire();
      }
    }
  } finally {
    unsubscribe(future, threadId);
  }
//    get(lockAsync(leaseTime, unit));
}


protected static final LockPubSub PUBSUB = new LockPubSub();

protected RFuture<RedissonLockEntry> subscribe(long threadId) {
  return PUBSUB.subscribe(getEntryName(), getChannelName(), commandExecutor.getConnectionManager().getSubscribeService());
}

protected void unsubscribe(RFuture<RedissonLockEntry> future, long threadId) {
  PUBSUB.unsubscribe(future.getNow(), getEntryName(), getChannelName(), commandExecutor.getConnectionManager().getSubscribeService());
}

這里會(huì)訂閱Channel,當(dāng)資源可用時(shí)可以及時(shí)知道,并搶占,防止無(wú)效的輪詢而浪費(fèi)資源

當(dāng)資源可用用的時(shí)候,循環(huán)去嘗試獲取鎖,由于多個(gè)線程同時(shí)去競(jìng)爭(zhēng)資源,所以這里用了信號(hào)量,對(duì)于同一個(gè)資源只允許一個(gè)線程獲得鎖,其它的線程阻塞

5. 小結(jié)

6. 其它相關(guān)

基于Redis的分布式鎖的簡(jiǎn)單實(shí)現(xiàn)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot?分模塊開(kāi)發(fā)的操作方法

    SpringBoot?分模塊開(kāi)發(fā)的操作方法

    這篇文章主要介紹了SpringBoot?分模塊開(kāi)發(fā)的操作方法,通過(guò)在原項(xiàng)目新增一個(gè)maven模塊,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 阿里云OSS基于java使用詳解

    阿里云OSS基于java使用詳解

    這篇文章主要介紹了阿里云OSS基于java使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • js判斷是否是移動(dòng)設(shè)備登陸網(wǎng)頁(yè)的簡(jiǎn)單方法

    js判斷是否是移動(dòng)設(shè)備登陸網(wǎng)頁(yè)的簡(jiǎn)單方法

    這篇文章主要介紹了js判斷是否是移動(dòng)設(shè)備登陸網(wǎng)頁(yè)的簡(jiǎn)單方法,需要的朋友可以參考下
    2014-02-02
  • spring的事務(wù)傳播屬性REQUIRED_NESTED原理

    spring的事務(wù)傳播屬性REQUIRED_NESTED原理

    這篇文章主要介紹了spring的事務(wù)傳播屬性REQUIRED_NESTED原理,在spring中,要想使用事務(wù)中的回滾點(diǎn),可以使用傳播屬性NESTED,需要的朋友可以參考下
    2023-05-05
  • idea中如何連接hive

    idea中如何連接hive

    這篇文章主要介紹了idea中如何連接hive問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 掌握模塊化開(kāi)發(fā)Spring Boot子模塊使用技巧

    掌握模塊化開(kāi)發(fā)Spring Boot子模塊使用技巧

    這篇文章主要為大家介紹了掌握模塊化開(kāi)發(fā)Spring Boot子模塊使用技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 淺談如何在項(xiàng)目中使用Spring Cloud Alibaba Sentinel組件

    淺談如何在項(xiàng)目中使用Spring Cloud Alibaba Sentinel組件

    隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要。本文主要介紹了使用Spring Cloud Alibaba Sentinel組件,感興趣的可以了解一下
    2021-07-07
  • java中spi使用詳解

    java中spi使用詳解

    java中spi(service provider interface)是jdk內(nèi)置的一種服務(wù)發(fā)現(xiàn)機(jī)制,可以基于配置,在運(yùn)行時(shí)加載指定服務(wù)。這篇文章主要介紹了java中spi使用,需要的朋友可以參考下
    2020-09-09
  • Java分層開(kāi)發(fā)必知之PO、BO、DTO、VO、POJO概念實(shí)例詳解

    Java分層開(kāi)發(fā)必知之PO、BO、DTO、VO、POJO概念實(shí)例詳解

    Java編程模型是一種在軟件開(kāi)發(fā)中幫助組織和管理代碼的框架,其中,VO,BO,PO,DO,以及DTO是一些關(guān)鍵概念,它們?cè)诓煌瑢哟魏碗A段起到重要作用,這篇文章主要介紹了Java分層開(kāi)發(fā)必知之PO、BO、DTO、VO、POJO概念的相關(guān)資料,需要的朋友可以參考下
    2026-02-02
  • Java如何實(shí)現(xiàn)密碼加密

    Java如何實(shí)現(xiàn)密碼加密

    這篇文章主要介紹了Java如何實(shí)現(xiàn)密碼加密,幫助大家更好的理解和學(xué)習(xí)java,感興趣的朋友可以了解下
    2020-08-08

最新評(píng)論

马鞍山市| 大新县| 乐陵市| 岳西县| 兴城市| 防城港市| 江油市| 界首市| 江山市| 阜宁县| 曲水县| 乐平市| 苗栗市| 祁东县| 荔浦县| 会东县| 葫芦岛市| 长乐市| 鸡西市| 微山县| 资兴市| 永康市| 墨竹工卡县| 肥西县| 佳木斯市| 江津市| 攀枝花市| 东阳市| 彭山县| 南昌市| 卓尼县| 玉树县| 张家口市| 玉林市| 阜阳市| 开江县| 开鲁县| 合山市| 大安市| 都兰县| 峨山|