Redis source code analysis: detailed explanation of Redis super utility class library Redisson

Please add image description

Redisson tool class library

I recommend a tool class library based on Redis development. This class library provides many practical functions, such as current limiting, bloom filter, distributed lock, etc.!

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

We will only analyze the implementation of distributed locks today. Redisson provides many ways to lock, such as non-blocking locks, blocking locks, and fair locks.

In addition, an automatic delay function is provided. When a task is not completed, Redisson will continue to extend the lock period through Watch Dog.

Blocking acquire lock

// 阻塞式获取锁,并且是重入锁
RLock lock = client.getLock("testLock");
try {
    
    
    lock.lock();
    lock.lock();

	// 执行业务逻辑
	
} finally {
    
    
    lock.unlock();
    lock.unlock();
}

non-blocking lock acquisition

RLock lock = client.getLock("lock");
if (lock.tryLock()) {
    
    
    System.out.println("获锁成功");
} else {
    
    
    System.out.println("获锁失败");
}

How does Redisson implement a reentrant lock?

lock execution script

script input

parameter meaning
KEYS[1] lock name
ARGV[1] Lock timeout (milliseconds)
ARGV[2] Client Unique ID: Thread ID
// 锁不存在
if (redis.call('exists', KEYS[1]) == 0) then
    // 新建锁,加锁次数设为1,并设置超时时间
    redis.call('hincrby', 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
    // 当前线程已经获取到锁了,将加锁次数加1
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end;
// 加锁失败
return redis.call('pttl', KEYS[1]);

Returns nil if the lock is successful, otherwise returns the remaining time of the lock

Unlock execution script

script input

parameter meaning
KEYS[1] lock name
KEYS[2 Unlock the channel of the message, the channel name, redisson_lock__channel:{lock name}
ARGV[1] Fixed to 0, Redisson defines the unlock message to be fixed to 0
ARGV[2] lock timeout
ARGV[3] Client Unique ID: Thread ID
// 为0表示锁不存在
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
    return nil;
end;
// 将加锁次数减1
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) then
    // 当前线程持有锁,设置超时时间
    redis.call('pexpire', KEYS[1], ARGV[2]);
    return 0;
else
	// 加锁次数为0了,直接删除锁,并广播释放锁的消息
    redis.call('del', KEYS[1]);
    redis.call('publish', KEYS[2], ARGV[1]);
    return 1;
end;
return nil;

Why do you want to publish a message when the unlock is successful?

Because the thread that acquires the lock by blocking does not keep trying to acquire the lock all the time, it will block. When it receives the unlock message, it will wake up and start to grab the lock again.

How does Redisson implement automatic delay of locks?

In order to prevent the lock from being released correctly, we usually need to set a timeout for the lock, but this will introduce new problems.

If the lock timeout is set to 10s, but the task is not executed within 10s, the lock will be released, and other threads will have problems acquiring the lock.

In order to solve this problem, Redisson provides a mechanism for automatic delay of watch dog, that is, when the lock is successful. Open a background thread, pass in the threadId of the successful lock, and the background thread checks every 10s to see if the thread currently holding the lock is the threadId. .
insert image description here
It should be noted that the specified timeout time cannot be displayed when locking, otherwise the watchdog will not take effect

When the timeout time of the specified lock is not displayed when locking, the timeout time of the lock is the lockWatchdogTimeout property of the Config class. The default value of this property is 30s (configurable), and the time for automatic watchdog checking is always equal to the timeout time of the lock. 1/3

Reference blog

[1]https://www.cnblogs.com/huangwentian/p/14622441.html?share_token=901429ee-a792-4f2a-87f9-20c47b7cc91c

Guess you like

Origin blog.csdn.net/zzti_erlie/article/details/123307897