"Trivia" in Redisson

foreword

In application development, especially web engineering development, it is usually concurrent programming, either multi-process or multi-thread. In this scenario, thread concurrency security issues are prone to occur, and locks have to be used to solve the problem. In multi-threaded high-concurrency scenarios, in order to ensure the thread safety of resources, jdk provides us with synchronized keywords and ReentrantLock reentrant locks, but they can only guarantee thread safety within a project. At present, when distributed clusters, microservices, and cloud native are rampant, how to ensure the thread safety of different processes, services, and machines, jdk does not provide us with existing solutions. At this point, we have to implement it manually with the help of related technologies. The current mainstream implementation methods are as follows:

  1. Based on mysql relational implementation
  2. Realization based on redis non-relational data
  3. Implementation based on zookeeper/etcd

insert image description here

Lock classification

Pessimistic lock : With strong exclusive and exclusive characteristics, the data is locked during the entire data processing process. It is suitable for more writes and will block read operations.
Optimistic locking : A more relaxed locking mechanism is adopted, mostly based on data version (Version) and timestamp. . It is suitable for reading more and will not block reading

Exclusive locks, mutex locks, exclusive locks : Guaranteed to be exclusively and exclusively held by only one thread at any time. synchronized, ReentrantLock
shared lock : can be shared and held by multiple threads at the same time. CountDownLatch countdown counter, Semaphore semaphore

Reentrant lock : also known as recursive lock. When the same thread acquires the lock in the outer method, it will automatically acquire the lock when entering the inner method.
Non-reentrant locks :

Fair locks : locks with priority, first come, first served, whoever applies for the lock first will get the lock first
Unfair lock : locks without priority, latecomers also have the opportunity to get the lock first

Spin lock : When a thread fails to acquire a lock (the lock is already occupied by other threads), an infinite loop retries to try to acquire a lock .
Blocking lock : When a thread fails to acquire a lock, the thread enters a blocked state until it is awakened after receiving a signal . Higher performance in highly competitive situations

Read lock : shared lock
Write lock : exclusive exclusive lock

Biased lock : always accessed by a thread, then the thread will automatically acquire the lock
Lightweight lock (CAS): when the lock is a biased lock, accessed by another thread, the biased lock will be upgraded to a lightweight lock ,
other threads will try to acquire the lock in the form of spin, which will not block and improve performance.
Heavyweight lock : When the lock is a lightweight lock, although another thread is spinning, the spin will not continue forever. When the spin is a certain number of times (10 times),
the lock has not been acquired yet It will enter blocking, and the lock will expand to a heavyweight lock. Heavyweight locks will cause the thread he applied for to block and reduce performance.
The above is actually a synchronized lock upgrade process

Table-level lock : lock the entire table, fast locking and low overhead, no deadlocks, but low concurrency, which will increase the probability of lock conflicts
Row-level lock : the smallest granularity lock in mysql, only for operation rows, It can greatly reduce the probability of lock conflicts, with high concurrency, but slow locking, high overhead, and deadlocks

Redisson

RedissonIt 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.

insert image description here

RedissonThe bottom layer is the Nettyframework. Redis 2.8The above version is supported, the above Java1.6+version is supported.

Reentrant Lock

The Redisson distributed reentrant lock RLockJava object based on Redis implements the java.util.concurrent.locks.Lockinterface.

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 (timer timer) that monitors the lock. 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 modified Config.lockWatchdogTimeoutto specify otherwise.

RLockThe object fully conforms to Java's Lock specification. That is to say, only the process that owns the lock can unlock it, and an error will be thrown if other processes unlock it IllegalMonitorStateException.

In addition, Redisson also leaseTimespecifies the locking time through the parameters provided by the locking method. 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();
   }
}

1. Introduce dependencies

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

2. Add configuration

@Configuration
public class RedissonConfig {
    
    

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

3. Use in the code

@Autowired
private RedissonClient redissonClient;

public void checkAndLock() {
    
    
    // 加锁,获取锁失败重试
    RLock lock = this.redissonClient.getLock("lock");
    lock.lock();

    // todo 一些处理业务

    // 释放锁
    lock.unlock();
}

Fair Lock (Fair Lock)

The Redisson distributed reentrant fair lock based on Redis is also java.util.concurrent.locks.Lockan RLockobject that implements the 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.

Reentrant locks are based on luck, and the first request may not be the first to grab the lock
. Fair locks are based on network speed and hand speed, and there will be a queue inside to ensure the order

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)

Redis-based Redisson distributed interlocking RedissonMultiLockobjects can RLockassociate multiple objects as an interlocking, and each RLockobject 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 Redisson red lock RedissonRedLockobject based on Redis implements the locking algorithm introduced by Redlock . This object can also be used to associate multiple RLockobjects as a red lock, and each RLockobject 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 RReadWriteLockJava object based on Redis implements the java.util.concurrent.locks.ReadWriteLockinterface. 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();
concurrent operation Can it be concurrent
write and write cannot be concurrent
read and write cannot be concurrent
read and read Can be concurrent

Semaphore

Redisson's distributed semaphore ( Semaphore ) Java object based on Redis RSemaphoreadopts a java.util.concurrent.Semaphoresimilar interface and usage. At the same time, it also provides asynchronous (Async) , reflective (Reactive) and RxJava2 standard interfaces.

RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.trySetPermits(3);
//尝试获取许可,如果成功就会继续执行,否则就会被阻塞
semaphore.acquire();
//释放许可供其他线程使用,之前被阻塞的线程会被唤醒继续执行
semaphore.release();

SemaphoreIt is generally used for traffic control, especially in application scenarios with limited public resources. For example, for database connections, assuming that the number of database connections is 10, multiple threads can use Semaphore to control the number of concurrent database threads up to 10.

For example, there are only three parking spaces in the parking lot of a shopping mall, and there are ten cars outside that need to come in. At this time, it must be ensured that only three cars can enter the parking lot at the same time, and other cars can only drive in when there are empty parking spaces.

Latch (CountDownLatch)

The Redisson distributed lock ( CountDownLatch ) Java object based on Redisson RCountDownLatchadopts a java.util.concurrent.CountDownLatchsimilar interface and usage.

RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();

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

JUCThe CountDownLatchrole in can only be limited to a single JVM, once the cluster is deployed, it cannot be guaranteed

Guess you like

Origin blog.csdn.net/weixin_43847283/article/details/128515680