ロック]分散05-原則セマフォとされたCountDownLatchで[使用Redisson

序文

すでにほとんどのコンテンツRedissonの書かれたように、我々は公式サイトRedisson成分の合計を見てみましょう。

image.pngimage.png

セマフォとされたCountDownLatchを残りの二つは、私たちが進捗状況を構築し、迅速Redissonはそれを達成する方法について説明します、があります。

我々はすべて言っても過言でありません、JDKでたCountDownLatchセマフォと2人の兄弟を知って、戻って見ることができます理解していません。

使用のセマフォ例

次の図の下のセマフォの外観:

image.pngimage.png

その後、我々はRedissonを使用する場合を見てみましょう。

RSemaphore semaphore = redisson.getSemaphore("semaphore");
// 同时最多允许3个线程获取锁
semaphore.trySetPermits(3);

for(int i = 0; i < 10; i++) {
  new Thread(new Runnable() {

    @Override
    public void run() {
      try {
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]尝试获取Semaphore锁"); 
        semaphore.acquire();
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]成功获取到了Semaphore锁,开始工作"); 
        Thread.sleep(3000);  
        semaphore.release();
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]释放Semaphore锁"); 
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }).start();
}

セマフォソースの解析

そして、上記の例によると、私たちは、ソースコードの実装方法を参照してください。

最初のステップ:
semaphore.trySetPermits(3)。

public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
    @Override
    public boolean trySetPermits(int permits) {
        return get(trySetPermitsAsync(permits));
    }

    @Override
    public RFuture<Boolean> trySetPermitsAsync(int permits) {
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                "local value = redis.call('get', KEYS[1]); " +
                "if (value == false or value == 0) then "
                    + "redis.call('set', KEYS[1], ARGV[1]); "
                    + "redis.call('publish', KEYS[2], ARGV[1]); "
                    + "return 1;"
                + "end;"
                + "return 0;",
                Arrays.<Object>asList(getName(), getChannelName()), permits);
    }

}

実装プロセス:

  1. 現在の値を取得するために、セマフォ取得
  2. セマフォがロックを取得するために、クライアントは数3に設定されている許可することができつつ、第1のデータは、その後、3セマフォセット、0であります
  3. そして、リターンをいくつかのニュースを公開する1

そして、見とるsemaphore.acquire();semaphore.release();ロジックを:

public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
    @Override
    public RFuture<Boolean> tryAcquireAsync(int permits) {
        if (permits < 0) {
            throw new IllegalArgumentException("Permits amount can't be negative");
        }
        if (permits == 0) {
            return RedissonPromise.newSucceededFuture(true);
        }

        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                  "local value = redis.call('get', KEYS[1]); " +
                  "if (value ~= false and tonumber(value) >= tonumber(ARGV[1])) then " +
                      "local val = redis.call('decrby', KEYS[1], ARGV[1]); " +
                      "return 1; " +
                  "end; " +
                  "return 0;",
                  Collections.<Object>singletonList(getName()), permits);
    }

    @Override
    public RFuture<Void> releaseAsync(int permits) {
        if (permits < 0) {
            throw new IllegalArgumentException("Permits amount can't be negative");
        }
        if (permits == 0) {
            return RedissonPromise.newSucceededFuture(null);
        }

        return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_VOID,
            "local value = redis.call('incrby', KEYS[1], ARGV[1]); " +
            "redis.call('publish', KEYS[2], value); ",
            Arrays.<Object>asList(getName(), getChannelName()), permits);
    }

}

ロックされたロジックを見てみましょうtryAcquireAsync()

  1. 、の現在の値を取得するために、セマフォ取得3,3> 1言います
  2. 1セマフォdecrbyクライアントの数、ロックセマフォを獲得することを可能にする2 1だけデクリメントされます
  3. decrbyセマフォ1
  4. decrbyセマフォ1
  5. 3つのロックを行った後、セマフォ値が0であります

再び直接ロックされ、この時間が0を返す場合、その後、以下に示すように、ロックを取得する無限ループに入ります。

image.pngimage.png

そして、ロック解除のロジックを見てみましょうreleaseAsync()

  1. incrbyは、クライアントがロックを解放するたびに、それは1の累積量の値に信号を1セマフォ、セマフォの値が0ではありません

理解するには、ここを参照してください、Redissonセマフォは実際には非常に簡単です達成

使用されたCountDownLatchの例

ユースケース:

RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(3);
System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]设置了必须有3个线程执行countDown,进入等待中。。。"); 

for(int i = 0; i < 3; i++) {
  new Thread(new Runnable() {

    @Override
    public void run() {
      try {
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]在做一些操作,请耐心等待。。。。。。"); 
        Thread.sleep(3000); 
        RCountDownLatch localLatch = redisson.getCountDownLatch("anyCountDownLatch");
        localLatch.countDown();
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]执行countDown操作"); 
      } catch (Exception e) {
        e.printStackTrace(); 
      }
    }

  }).start();
}

latch.await();
System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]收到通知,有3个线程都执行了countDown操作,可以继续往下走"); 

たCountDownLatchソースの解析

ソースとして、次のとおりです。

 public class RedissonCountDownLatch extends RedissonObject implements RCountDownLatch {

    @Override
    public RFuture<Boolean> trySetCountAsync(long count) {
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                "if redis.call('exists', KEYS[1]) == 0 then "
                    + "redis.call('set', KEYS[1], ARGV[2]); "
                    + "redis.call('publish', KEYS[2], ARGV[1]); "
                    + "return 1 "
                + "else "
                    + "return 0 "
                + "end",
                Arrays.<Object>asList(getName(), getChannelName()), newCountMessage, count);
    }

    @Override
    public RFuture<Void> countDownAsync() {
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                        "local v = redis.call('decr', KEYS[1]);" +
                        "if v <= 0 then redis.call('del', KEYS[1]) end;" +
                        "if v == 0 then redis.call('publish', KEYS[2], ARGV[1]) end;",
                    Arrays.<Object>asList(getName(), getChannelName()), zeroCountMessage);
    }



}

第1の解析trySetCount()方法のロジック:

  1. anyCountDownLatchが初めて、存在は確かに存在しません。
  2. セットredisson_countdownlatch__channel__anyCountDownLatch 3
  3. 戻る1

次の分析のlatch.await();下に示されているような方法:

image.pngimage.png

この方法は、実際にはそれ以外の場合は、死のサイクルから撤退し、常にそれから、値anyCountDownLatchを取得した値がゼロより大きい場合、死のサイクルを継続し、しばらく真のループに陥っています

最後にlocalLatch.countDown();方法:

  1. DECR anyCountDownLatch、つまり、毎回クライアントを行うカウントダウン操作は、実際には、1 cocuntDownLatchの値を小さくします
  2. await()態様は、0がその独自のロジックを実行する場合anyCountDownLatchに対応する格納された値が、0であるかどうか、判断する無限ループを分析しました

概要

二つの成分は非常に単純ではありませんここを参照してください?

ここに、学習のRedisson部分が終わって、我々は分散ロックを実装ZKの原理を学びます。

宣言

:私のブログから始まるこの記事https://www.cnblogs.com/wang-mengと公共番号:ロマンチックみなさ一つramiflorous BEは、ソースを明記してください転載必要があります!

興味のパートナーは、個々の国民の少数心配することができる:一つの枝にはロマンチックな花を数えます

おすすめ

転載: www.cnblogs.com/wang-meng/p/12548492.html