分布式锁-Redission可重入锁原理

一、概述

Redisson 可重入锁是一种分布式锁,它基于 Redis 实现。可重入指的是同一个线程在持有锁的情况下,可以多次获取该锁而不会造成死锁。

-----它可以在分布式系统中用于实现互斥锁。这种锁可以允许多个线程同时获取锁,但在任何给定时间只有一个线程可以执行受保护的代码块。
-----Redission锁提供了一种简单的方法来保证在分布式系统中的互斥性,同时支持可重入性。这意味着一个线程可以在获取锁之后再次获取同一个锁,而不需要等待锁释放。

二、原理

1、当线程 A 尝试获取锁时,它会向 Redis 服务器发送 SETNX 命令来尝试将锁的键设置为特定的值。如果 SETNX 命令返回成功,说明线程 A 成功获取了锁。
2、如果 SETNX 命令返回失败,说明锁的键已经被其他线程持有,这时 Redisson 会检查当前持有锁的线程是否是同一个线程。如果是,则允许该线程再次获取锁,并将锁的计数器加一。
3、如果 SETNX 命令返回失败且当前持有锁的线程不是同一个线程,则表示其他线程已经持有了锁,此时线程 A 需要等待。
4、线程 A 在等待期间会使用 Redis 的订阅与发布功能(Pub/Sub)来订阅锁的释放事件。
5、当持有锁的线程释放锁时,Redis 服务器会发布一个锁释放的消息。线程 A收到消息后会重新尝试获取锁。

通过以上的机制,Redisson 实现了可重入锁的功能。它能够保证同一个线程可以多次获取锁,而其他线程在锁被持有期间会进入等待状态。
需要注意的是,为了避免死锁,线程必须释放它所持有的所有锁,即锁的计数器必须归零。只有当锁的计数器为零时,其他线程才能获取该锁。

其中对于获得锁和释放锁,redisson底层也是采用了lua脚本来实现的,不仅实现了锁的可重用性,还保证了分布式锁的原子性
添加锁脚本

	"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]);"

删除锁Lua脚本

			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;

测试示例:

分布式锁-Redission可重入锁原理_第1张图片在分布式锁中,他采用hash结构用来存储锁,其中大key表示表示这把锁是否存在,用小key表示当前这把锁被哪个线程持有,value代表该线程锁的重数
上述图:

Key------->大key 大key表示表示这把锁是否存在
field------->小key 小key表示当前这把锁被哪个线程持有
value------->value代表该线程锁的重数

你可能感兴趣的:(Redis,黑马点评,分布式)