使用复述分布式锁解决并发线程资源共享问题

  

<强>前言

  

众所周知,在多线程中,因为共享全局变量,会导致资源修改结果不一致,所以需要加锁来解决这个问题,保证同一时间只有一个线程对资源进行操作

  

但是在分布式架构中,我们的服务可能会有n个实例,但线程锁只对同一个实例有效,就需要用到分布式锁——复述setnx

  

<强>原理
  

  

修改某个资源时,在复述中设置一个键,值根据实际情况自行决定如何表示

  

我们既然要通过检查关键是否存在(存在表示有线程在修改资源,资源上的锁,其他线程不可同时操作,若关键不存在,表示资源未被线程占用,允许线程抢占,然后将通过setnx设置vlaue,表示资源上的锁,其他线程不可同时操作)

  

图示:   

使用复述分布式锁解决并发线程资源共享问题

  

<>强分析

  

我们的服务处于一个集群中,如果只是简单的的使用线程锁来解决以上问题,是存在问题的:因为线程是基于进程的,两个web服务器处于不同的进程空间

  

也就是说,user1的请求发往网络server1,那只能与web server1的其他请求进行锁的操作,而不能对web server2的请求产生影响

  

上面的图中,user1发往网络server1的请求负责处理的线程为Thread1,同理负责处理user2发往网络server2的请求的线程thread2

  

在同一时刻1,两个线程都读取了mysql中residue_ticket的值为100,对应上图(1)(2),各自100年对进行1操作,更新到数据库,对应(3)(4)

  

我们预期的情况是residue_ticket值被减少了两次,应该为98,但是实际情况下,两个线程都做了100 - 1=99的操作,并都将mysql中的值改为了99年的这就会导致最终数据不一致,所以就要用到分布式锁。

  

<强>为什么用复述,# 63;
  

  

因为复述是单线程的,不存在多线程资源竞争,并且它真的很快

  

<强>为什么用setnx而不是集# 63;
  

  

setnx表示只有在关键不存在时才能设置成功,但是组会在关键的存在的情况下修改值

  

利用setnx的特性,我们可以这样这样设计:

  

<>强伪代码:

        #设置复述,锁的   复述,关键=' residue_ticket_lock '      # get_ticket是处理购票的逻辑   def get_ticket ():   time_out=5 #为了防止线程过多,当前线程获取不到锁,长时间处于循环中而导致的性能影响,我们设置一个超时时间,如果当前线程在超时时间内还没有抢占到分布式锁,就返回失败的结果   而真正的:   如果redis.setnx (‘residue_ticket_lock’,‘锁’,5):   #如果setnx返回真,表示此刻没有其他线程在操作数据库,当前线程可以上锁成功,注意不仅设置了价值=https://www.yisu.com/zixun/lock,还设置了过期时间,这是必要的,为了防止上锁的线程异常崩掉导致不能释放(删除键)而导致其他所有线程永远拿不到操作权   residue_ticket=mysql.get (residue_ticket) #从mysql中获取当前剩余票数   mysql.update (residue_ticket, residue_ticket-1) #订购成功,将票数1,更新数据到mysql   #删除键,释放锁   redis.del (“residue_ticket”)   还真   其他:   #如果setnx返回假,表示有其他线程对在操作,当前线程等待0.01 s,并继续循环   time . sleep (0.01)   time_out -=0.01   继续   返回False      

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

使用复述分布式锁解决并发线程资源共享问题