lua游戏脚本实例源码_Redisson公平锁源码分析
分析 Redisson 公平锁 FairLock 的 lock ⽅法源码。RedissonFaireLock 是 RedissonLock 的⼦类。公平锁实现逻辑主要重载了 tryLockInnerAsync ⽅法。⽽ tryLockInnerAsync ⽅法的加锁逻辑,⼏乎是⽤ lua 脚本实现。
本⽂主要是对 lua 脚本代码逻辑的分析。⼿⼯画图,不贴源码~
分析⽬标代码
RLock lock  = FairLock("myLock");
lock.lock();
关键步骤
1. 实例化名称为 'myLock' 的 RedissonFaireLock
2. 实例化 RedissonFaireLock ,构造⽅法中会根据 'myLock' ⽣成 NodeSource ,作为通信服务的组件
3. RedissonFaireLock 继承了 RedissonLock ,重载⽅法 tryLockInnerAsync。公平锁的实现,就是主要
在该⽅法中的 lua 脚本实
现。源码架构图对应的就是 Lua 脚本逻辑
Lua 脚本主要的逻辑是,线程公平占有锁,是通过 redisson_lock_queue 队列来实现。锁的超时时间,是通过 zset 来做承载线程占⽤不到锁资源,则就进⼊ redisson_lock_queue 队列排队等待
参数说明
1. 锁名称为:name => 'myLock'
2. 超时时间,默认为:threadTimeout => 5000
3. 线程排队的队列:threadsQueueName => redisson_lock_queue:{myLock}
4. 线程超时zset:timeoutSetName => redisson_lock_timeout:{myLock}
源码架构图
Lua 脚本
"while true do " +
"local firstThreadId2 = redis.call('lindex', KEYS[2], 0);" +
"if firstThreadId2 == false then " +
"break;" +
"end;" +
"local timeout = tonumber(redis.call('zscore', KEYS[3], firstThreadId2));" +    "if timeout <= tonumber(ARGV[4]) then " +
// remove the item from the queue and timeout set
// NOTE we do not alter any other timeout
"redis.call('zrem', KEYS[3], firstThreadId2);" +
"redis.call('lpop', KEYS[2]);" +
"else " +
"break;" +
"end;" +
"end;" +
// check if the lock can be acquired now
"if (redis.call('exists', KEYS[1]) == 0) " +
"and ((redis.call('exists', KEYS[2]) == 0) " +
"or (redis.call('lindex', KEYS[2], 0) == ARGV[2])) then " +
// remove this thread from the queue and timeout set
"redis.call('lpop', KEYS[2]);" +
"redis.call('zrem', KEYS[3], ARGV[2]);" +
// decrease timeouts for all waiting in the queue
"local keys = redis.call('zrange', KEYS[3], 0, -1);" +
"for i = 1, #keys, 1 do " +
"redis.call('zincrby', KEYS[3], -tonumber(ARGV[3]), keys[i]);" +
"end;" +
// acquire the lock and set the TTL for the lease
"redis.call('hset', KEYS[1], ARGV[2], 1);" +
"redis.call('pexpire', KEYS[1], ARGV[1]);" +
"return nil;" +
"end;" +
// check if the lock is already held, and this is a re-entry
"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;" +
// the lock cannot be acquired
// check if the thread is already in the queue
"local timeout = redis.call('zscore', KEYS[3], ARGV[2]);" +
"if timeout ~= false then " +
// the real timeout is the timeout of the prior thread
// in the queue, but this is approximately correct, and
// avoids having to traverse the queue
"return timeout - tonumber(ARGV[3]) - tonumber(ARGV[4]);" +
"end;" +
// add the thread to the queue at the end, and set its timeout in the timeout set to the timeout of // the prior thread in the queue (or the timeout of the lock if the queue is empty) plus the
// threadWaitTime
"local lastThreadId = redis.call('lindex', KEYS[2], -1);" +
手机游戏源码论坛"local ttl;" +
"if lastThreadId ~= false and lastThreadId ~= ARGV[2] then " +
"ttl = tonumber(redis.call('zscore', KEYS[3], lastThreadId)) - tonumber(ARGV[4]);" +
"else " +
"ttl = redis.call('pttl', KEYS[1]);" +
"end;" +
"local timeout = ttl + tonumber(ARGV[3]) + tonumber(ARGV[4]);" +
"if redis.call('zadd', KEYS[3], timeout, ARGV[2]) == 1 then " +
"redis.call('rpush', KEYS[2], ARGV[2]);" +
"end;" +
"return ttl;",
- End -

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。