当前位置: 首页 > news >正文

携程网站的会计工作怎么做高端seo服务

携程网站的会计工作怎么做,高端seo服务,营销网页制作教程,手机网站建设 移商动力我们来看一下第二种redis分布式锁 第一种锁是可重入锁,非公平可重入锁,所谓的非公平可重入锁是什么意思呢?胡乱的争抢,根本没有任何公平性和顺序性可言 第二种锁,可重入锁,公平锁 通过公平锁&#xff0c…

我们来看一下第二种redis分布式锁

第一种锁是可重入锁,非公平可重入锁,所谓的非公平可重入锁是什么意思呢?胡乱的争抢,根本没有任何公平性和顺序性可言

第二种锁,可重入锁,公平锁

通过公平锁,可以保证,客户端获取锁的顺序,就跟他们请求获取锁的顺序,是一样的,公平锁,排队,谁先申请获取这把锁,谁就可以先获取到这把锁,这个是按照顺序来的

会把各个客户端对加锁的请求进行排队处理,保证说先申请获取锁的,就先可以得到这把锁,实现所谓的公平性

可重入非公平锁、公平锁,他们在整体的技术实现上都是一样的,只不过唯一不同的一点就是在于加锁的逻辑那里

RLock fairLock = redisson.getFairLock("anyLock");
fairLock.lock();
fairLock.unlock();

这个代码就是获取公平锁的方法。
RedissonFairLock是RedissonLock的子类,整体的锁的技术框架的实现,都是跟之前讲解的RedissonLock是一样的,无非就是重载了一些方法,加锁和释放锁的lua脚本的逻辑稍微复杂了一些,别的没什么特别的
在这里插入图片描述

第一个线程第一次加锁

我们来分析一下这个加锁的lua脚本

if (command == RedisCommands.EVAL_LONG) {return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,// remove stale threads"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 "+ "redis.call('zrem', KEYS[3], firstThreadId2); "+ "redis.call('lpop', KEYS[2]); "+ "else "+ "break;"+ "end; "+ "end;"+ "if (redis.call('exists', KEYS[1]) == 0) and ((redis.call('exists', KEYS[2]) == 0) "+ "or (redis.call('lindex', KEYS[2], 0) == ARGV[2])) then " +"redis.call('lpop', KEYS[2]); " +"redis.call('zrem', KEYS[3], ARGV[2]); " +"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; " +"local firstThreadId = redis.call('lindex', KEYS[2], 0); " +"local ttl; " + "if firstThreadId ~= false and firstThreadId ~= ARGV[2] then " + "ttl = tonumber(redis.call('zscore', KEYS[3], firstThreadId)) - tonumber(ARGV[4]);" + "else "+ "ttl = redis.call('pttl', KEYS[1]);" + "end; " + "local timeout = ttl + tonumber(ARGV[3]);" + "if redis.call('zadd', KEYS[3], timeout, ARGV[2]) == 1 then " +"redis.call('rpush', KEYS[2], ARGV[2]);" +"end; " +"return ttl;", Arrays.<Object>asList(getName(), threadsQueueName, timeoutSetName), internalLockLeaseTime, getLockName(threadId), currentTime + threadWaitTime, currentTime);
}

首先,第一行while true do 进入一个while的死循环
第二行local firstThreadId2 = redis.call(‘lindex’, KEYS[2], 0);

先看一下KEYS[2]这个参数是什么,也就是这部分lua脚本下面那个List里面第二个参数,第一个是getName(),不用想肯定是和我们传的“anyLock”有关,那第二个KEYS[2] = threadsQueueName = redisson_lock_queue:{anyLock},基于redis的数据结构实现的一个队列,第三个KEYS[3] = timeoutSetName = redisson_lock_timeout:{anyLock} 基于redis的数据结构实现的一个Set数据集合,有序集合,可以自动按照你给每个数据指定的一个分数(score)来进行排序
ARGV = internalLockLeaseTime, getLockName(threadId), currentTime
ARGV[1] = 30000毫秒
ARGV[2] = UUID:threadId 与线程有关
ARGV[3] = 当前时间(10:00:00) + 5000毫秒 = 10:00:05
ARGV[4] = 当前时间(10:00:00)

再回到lua脚本 local firstThreadId2 = redis.call(‘lindex’, KEYS[2], 0);
lindex 命令用于通过索引获取列表中的元素。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素
那这行的意思就是从名为redisson_lock_queue:{anyLock} 的队列数组中弹出来下标为0的元素,也就是队列中的第一个元素

下一行,如果不存在的话,直接跳出while循环

if firstThreadId2 == false then "+ "break;"
+ "end;

那我们第一次加锁的时候,肯定是不存在的,所以往下看其他逻辑
这里有几个判断,第一个exists anyLock 这个锁是否存在,不存在,返回true
第二个和第三个是or
第二个exists redisson_lock_queue:{anyLock},队列是否存在,不存在,返回true
第三个lindex redisson_lock_queue:{anyLock} 弹出第一个元素,是否等于 UUID:threadId 这个是要返回false,但是第二和第三个判断 是or,所以第二第三只要有一个true就成立了

if (redis.call('exists', KEYS[1]) == 0) and ((redis.call('exists', KEYS[2]) == 0) "+ "or (redis.call('lindex', KEYS[2], 0) == ARGV[2])) then

那继续往下走
lpop redisson_lock_queue:{anyLock},弹出队列的第一个元素,现在队列是空的,所以什么都不会干
zrem redisson_lock_timeout:{anyLock} UUID:threadId,从set集合中删除threadId对应的元素,此时因为这个set集合是空的,所以什么都不会干

hset anyLock UUID:threadId 1,加锁,这和之前的加锁逻辑一样,加一个名字为anyLock的map结构,键值对key:value 为“UUID:threadId”: 1

redis.call(‘pexpire’, KEYS[1], ARGV[1]); 给这个锁设置过期时间,默认30s
返回一个nil,在外层代码中,就会认为是加锁成功,此时就会开启一个watchdog看门狗定时调度的程序,每隔10秒判断一下,当前这个线程是否还对这个锁key持有着锁,如果是,则刷新锁key的生存时间为30000毫秒
这就是公平锁的加锁原理

第二个线程第一次加锁

那这是第一次加锁,后面是怎么实现公平锁? 再来看一下
第二个线程来尝试加锁,首先也是进入while true死循环,lindex redisson_lock_queue:{anyLock} 0,获取队列的第一个元素,此时队列还是空的,所以获取到的是false,直接退出while true死循环

再次进入这个判断,这次就有些不一样了
‘exists’, anyLock == 0 此时anyLock锁已经存在了,所以这个条件肯定就不成立了
那进行下面的判断
if (redis.call(‘hexists’, KEYS[1], ARGV[2]) == 1) then
这个是判断,在名为anyLock这个map锁的键值对中 有没有名为 “UUID-02:threadId-02” 的key,此时肯定也是不成立,因为现在就是这个线程第一次请求加锁的。
在这里插入图片描述
再往下就是排队的关键逻辑了,我们来分析一下
local firstThreadId = redis.call(‘lindex’, KEYS[2], 0);
取出来队列中的第一个元素
if firstThreadId ~= false and firstThreadId ~= ARGV[2] then
这是判断取出来的元素不为空,此时不成立
所以else中的逻辑 ttl = redis.call(‘pttl’, KEYS[1]);这个是获取 anyLock这个锁的剩余生存时间,假设是20000毫秒
继续往下local timeout = ttl + tonumber(ARGV[3]); 算出来 ttl + 当前时间 + 5000毫秒是什么时间
比如:当前是2023-01-01 10:00:00, 那么加上20000毫秒,再加 5000毫秒,结果就是10:00:25 的long型时间戳

if redis.call(‘zadd’, KEYS[3], timeout, ARGV[2]) == 1 then
在set有序集合redisson_lock_timeout:{anyLock} 中,新增一个线程是 UUID-02:threadId-02的数据,排序权重是2023-01-01 10:00:25的long型时间戳 ,并且新增成功的话,
rpush’, KEYS[2], ARGV[2]
在队列 redisson_lock_queue:{anyLock} 中也新增一个元素UUID-02:threadId-02的数据
最后返回一个anyLock的存活时间ttl,之前的逻辑还记得吧,如果加锁的时候返回有效期时间的话,也会进入一个while死循环不断地尝试加锁。重新执行lua脚本
后面的线程也是同理,timeout时间戳不断增大,有序集合redisson_lock_timeout:{anyLock} 中会按照这个权重自动排序,队列 redisson_lock_queue:{anyLock} 中也按照放入的顺序往后排。
在这里插入图片描述

第三个线程第一次加锁

这次进来这个lua脚本的时候就要进入这个逻辑中了
local firstThreadId2 = redis.call(‘lindex’, KEYS[2], 0); 判断队列中第一个元素是否存在,上面已经放进去了,肯定是存在的,而且这是第二个线程的
local timeout = tonumber(redis.call(‘zscore’, KEYS[3], firstThreadId2));
获取有序队列中,元素UUID-02:threadId-02的权重值。

if timeout <= tonumber(ARGV[4]) then
上面我们说了,这个权重值是2023-01-01 10:00:25的long型时间戳,那这里是判断当前时间的时间戳和这个相比。 意思就是,当前时间是否已经超过了2023-01-01 10:00:25。
这次我们先假设不成立,继续往下
在这里插入图片描述
exists’, KEYS[1] == 0 肯定也是不成立,已经存在了,
此时队列中第一个元素是UUID-02:threadId-02
ARGV[2] 是UUID-03:threadId-03
local firstThreadId = redis.call(‘lindex’, KEYS[2], 0);
那这里判断的两个条件成立
firstThreadId不等于空,并且不等于当前线程
if firstThreadId ~= false and firstThreadId ~= ARGV[2] then
这里获取的就是,第一个线程的权重时间戳-当前时间的时间戳,意思是,队列第一个线程还有多久会去竞争锁
然后再拿着这个时间差+当前时间+5s
这样一来,这个线程的权重在有序队列中,肯定是排在第一个线程后面的。
ttl = tonumber(redis.call(‘zscore’, KEYS[3], firstThreadId)) - tonumber(ARGV[4]);

然后就是入队,排队
if redis.call(‘zadd’, KEYS[3], timeout, ARGV[2]) == 1 then
redis.call(‘rpush’, KEYS[2], ARGV[2]);

此时我们看一下情况
在这里插入图片描述
如果超过的话,理论上来说anyLock这个锁已经被释放掉了。
那就把元素UUID-02:threadId-02从 有序集合redisson_lock_timeout:{anyLock} 中移除
redis.call(‘zrem’, KEYS[3], firstThreadId2);
队列redisson_lock_queue:{anyLock}中也把第一个元素删除
redis.call(‘lpop’, KEYS[2]);

http://www.hkea.cn/news/32301/

相关文章:

  • 适合友情链接的网站排名函数
  • 开发公司岗位设置广州seo招聘网
  • 国内web设计网站宣传推广
  • 深圳高端网站定制公司小时seo
  • wordpress主菜单下拉箭头怎么设置台州seo排名优化
  • 网站系统管理员模块关键词查找工具
  • 望江县建设局网站外贸seo推广招聘
  • 微信网站上传图片手机怎么制作网站
  • 简单做网站需要学什么搜索引擎有哪些网站
  • 网站备案信息加到哪里如何进行网站推广
  • 昭通网站制作aso优化技巧
  • 制作网站时怎样做滚动字幕新网站多久会被百度收录
  • 余姚物流做网站微信指数是搜索量吗
  • 怎样做网站轮播今日国内重大新闻事件
  • 想给大学做网站百度网盘搜索神器
  • jsp网站开发论文官方app下载安装
  • 关于机场建设的网站今日疫情最新情况
  • 网站域名注册服务商google浏览器官方
  • 通过网站开发工具怎么改自动跳网站百度指数有哪些功能
  • 可以发锚文本的网站百度搜索官方网站
  • 东莞网站建设企慕简述如何优化网站的方法
  • 可以做网站的公司seo外包
  • 自己怎么做网站视频赚钱5g网络优化培训
  • 数据库修改网站管理员密码seo网站有优化培训吗
  • 福田做商城网站建设找哪家公司好抖音怎么运营和引流
  • 厘米售卡站怎么做网站禁止搜索引擎收录的方法
  • 网站首页滚动图片怎么做谷歌搜索关键词排名
  • 嵩县网站开发友情链接获取的途径有哪些
  • 国家企业信息公示网(广东)海南快速seo排名优化
  • 高端网站设计 上海徐州seo排名公司