Interpretation of distributed locks in redisson

 overview

Redisson is a Java in-memory data grid (In-Memory Data Grid) implemented on the basis of Redis. It not only provides a series of distributed common Java objects, but also provides many distributed services. These include (BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service , Scheduler service) Redisson provides the easiest and most convenient way to use Redis. The purpose of Redisson is to promote users' separation of concerns about Redis (Separation of Concern), so that users can focus more on processing business logic.

 Official document address: https://github.com/redisson/redisson/wiki

 Simple configuration and use

pom.xml import dependencies

<dependency>
       <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.11.2</version>
</dependency>

add configuration

@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        // 可以用"rediss://"来启用SSL连接
        config.useSingleServer().setAddress("redis://172.16.116.100:6379");
        return Redisson.create(config);
   }
}

 code used in

   @Autowired
    private RedissonClient redissonClient;

    public void checkAndLock() {
        // 加锁,获取锁失败重试
        RLock lock = this.redissonClient.getLock("lock");
        lock.lock();
        // 先查询库存是否充足
        Stock stock = this.stockMapper.selectById(1L);
        // 再减库存
        if (stock != null && stock.getCount() > 0) {
            stock.setCount(stock.getCount() - 1);
            this.stockMapper.updateById(stock);
        }
        // 释放锁
        lock.unlock();
    }

Reentrant Lock 

The Redisson distributed reentrant lock RLock Java object based on Redis implements the java.util.concurrent.locks.Lock interface. Everyone knows that if the Redisson node responsible for storing the distributed lock goes down and the lock happens to be locked, the lock will appear locked. In order to avoid this situation, Redisson internally provides a watchdog that monitors locks. Its function is to continuously extend the validity period of the lock before the Redisson instance is closed. By default, the timeout period for the watchdog to check the lock is 30 seconds, and it can also be specified by modifying Config.lockWatchdogTimeout.

RLock objects are fully compliant with Java's Lock specification. That is to say, only the process that owns the lock can unlock it, and other processes will throw an IllegalMonitorStateException error. In addition, Redisson also provides the leaseTime parameter through the locking method to specify the locking time. After exceeding this time, the lock will be unlocked automatically.

RLock lock = redisson.getLock("anyLock");
// 最常见的使用方法
lock.lock();
// 加锁以后10秒钟自动解锁
// 无需调用unlock方法手动解锁
lock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       lock.unlock();
   }
}

 Fair Lock (Fair Lock)

The Redisson distributed reentrant fair lock based on Redis is also an
RLock object that implements the java.util.concurrent.locks.Lock interface. At the same time, it also provides asynchronous (Async), reflective (Reactive) and RxJava2 standard interfaces. It ensures that when multiple Redisson client threads request locks at the same time, they are assigned to the thread that made the request first. All request threads will be queued in a queue. When a thread goes down, Redisson will wait for 5 seconds before continuing to the next thread. That is to say, if there are 5 threads in the front waiting state, then the following thread will wait At least 25 seconds .

RLock fairLock = redisson.getFairLock("anyLock");
// 最常见的使用方法
fairLock.lock();
// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
fairLock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
fairLock.unlock();

Interlock (MultiLock) 

Redisson distributed interlocking RedissonMultiLock object based on Redis can associate multiple RLock objects as an interlock, and each RLock object instance can come from a different Redisson instance.

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
...
lock.unlock();

Red Lock (RedLock)

The RedissonRedLock object based on Redis implements the locking algorithm introduced by Redlock. This object can also be used to associate multiple RLock objects as a red lock, and each RLock object instance can come from a different Redisson instance.

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();

ReadWriteLock (ReadWriteLock) 

The Redisson distributed reentrant read-write lock RReadWriteLock Java object based on Redis implements
the java.util.concurrent.locks.ReadWriteLock interface. Among them, both the read lock and the write lock inherit the RLock interface. Distributed reentrant read-write locks allow multiple read locks and one write lock to be locked at the same time.

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常见的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
// 10秒钟以后自动解锁
// 无需调用unlock方法手动解锁
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 或
rwlock.writeLock().lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// 或
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

Add the StockController method:

    @GetMapping("test/read")
    public String testRead(){
        String msg = stockService.testRead();
        return "测试读";
    }
    @GetMapping("test/write")
    public String testWrite(){
        String msg = stockService.testWrite();
        return "测试写";
    }

Add the StockService method:

public String testRead() {
    RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
    rwLock.readLock().lock(10, TimeUnit.SECONDS);
    System.out.println("测试读锁。。。。");
    // rwLock.readLock().unlock();
    return null;
}
public String testWrite() {
    RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
    rwLock.writeLock().lock(10, TimeUnit.SECONDS);
    System.out.println("测试写锁。。。。");
    // rwLock.writeLock().unlock();
    return null;
}

Open two browser windows to test:

  • Simultaneous access to write: After one writes, wait for a while (about 10s), and another write starts
  • Simultaneous access read: no wait
  • Write first and then read: read and wait (about 10s) for writing to complete
  • Read first and then write: write to wait (about 10s) to complete the read 

Semaphore

Redis-based Redisson's distributed semaphore (Semaphore) The Java object RSemaphore adopts
an interface and usage similar to java.util.concurrent.Semaphore. At the same time, it also provides asynchronous (Async), reflective
(Reactive) and RxJava2 standard interfaces.

RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();
semaphore.release();

Add method in StockController:

@GetMapping("test/semaphore")
public String testSemaphore(){
    this.stockService.testSemaphore();
    return "测试信号量";
}

Add method in StockService:

    public void testSemaphore() {
        RSemaphore semaphore = this.redissonClient.getSemaphore("semaphore");
        semaphore.trySetPermits(3);
        try {
            semaphore.acquire();
            TimeUnit.SECONDS.sleep(5);
            System.out.println(System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Add test case: concurrent 10 times, loop once

Console effect:

 From this we can see:

  • 3 requests came in in 1606960790 seconds: 1 for each console
  • 3 requests came in in 1606960795 seconds: 1 request from console 2, 2 requests from console 3
  • 3 requests came in in 1606960800 seconds: 2 requests from console 1, 1 request from console 2
  • 1 request came in 1606960805 seconds: 1 request from console 1

Latch (CountDownLatch) 

The Redisson distributed locking (CountDownLatch) Java object RCountDownLatch based on Redisson adopts
the interface and usage similar to java.util.concurrent.CountDownLatch.

RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();
// 在其他线程或其他JVM里
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();

Two methods are required: one to wait and one to count countDown

Add a test method to StockController

    @GetMapping("test/latch")
    public String testLatch(){
        this.stockService.testLatch();
        return "班长锁门。。。";
    }
    @GetMapping("test/countdown")
    public String testCountDown(){
        this.stockService.testCountDown();
        return "出来了一位同学";
    }

Add test method to StockService

    public void testLatch() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.trySetCount(6);
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void testCountDown() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.trySetCount(6);
        latch.countDown();
    }

Restart the test and open two pages: the first request will not be executed until the second request is executed 6 times.

Summarize 

redisson: Java client of redis, distributed lock
    gameplay:
        1. Introduce dependencies
        2.java configuration class: RedissonConfig
            @Bean
            public RedissonClient redissonClient(){                 Config config = new Config();                 config.useSingleServer().setAddress("redis ://ip:port");                 return Redisson.create(config);             }         3. Code usage:             reentrant lock RLock object: CompletableFuture + lua script + hash                 RLock lock = this.redissonClient.getLock("xxx");                 lock.lock()/unlock()             fair lock:                 RLock lock = this.redissonClient.getFairLock("xxx");                 lock.lock()/unlock()








                



                
            Interlock and red lock:
            
            read-write lock:
                RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("xxx");
                rwLock.readLock().lock()/unlock();
                rwLock.writeLock().lock()/unlock( );
                
            Semaphore:
                RSemaphore semaphore = this.redissonClient.getSemaphore("xxx");
                semaphore.trySetPermits(3);
                semaphore.acquire()/release();
                
            Lockout:
                RCountDownLatch cdl = this.redissonClient.getCountDownLatch("xxx" );
                cdl. trySetCount(6);
                cdl. await()/countDowntch();

Guess you like

Origin blog.csdn.net/m0_62436868/article/details/130459721