Skip to content

简单聊聊分布式锁,以及如何实现

About 987 wordsAbout 3 min

分布式分布式锁

2024-05-27

在25号的软件架构师考试里面,就提到了关于分布式锁的实现以及中间存在的问题,这里简单做一个学习。

题目的大概得意思就是说,小王要做一个秒杀系统,在实现上,小王采用数据库来实现分布式锁;小李觉得数据库来实现的话,会有很大的风险,小李觉的使用redis+过期时间的方式来实现。

假设有一个stock的资源,初始值为1。

public static Long stock 1L;

如果说我们不加锁的话,在单线程的情况下是没有问题的,当判断stock的值是否等于1,如果等于1的话,stock-1,表示秒杀成功;否则秒杀失败。

但是在多线程的情况下,就不能保证stock不超卖,像下面这样。

public static void main(String[] args) throws Exception{
  for(int i=0;i<3;i++){
    new Thread(
    	()->{
        try{
          // 调用秒杀的方法
        }catch(Exception e){
          e.printStackTrace();
        }
      }
    ).start();
  }
}

如果想要在多线程的情况下,保证数据的一致性,我们就需要对资源进行加锁,我们可以用java的synchronized实现。

public static void placeOrder() throws Exception{
  // 加上同步锁
  synchronized(stock){
    if(stock>0){
      // 业务操作stock
      stock--;
    }
  }
}

这样子能保证一个在一个数据库里面stock是一致性的,但是说如果是分布式数据库的话,synchronized就没有办法了,因为他是jvm级的。

这个时候就会想到使用redis的setnx来实现,往redis里面set一个key,如果这个key有值的话,就表示这个资源正在被占用,其他请求需要等待资源的释放,但是这里存在一个问题,就是说服务器 挂掉的话,这个redis里面的值就没有办法的到释放。

所以需要加一个超时时间。

这也有一个问题,就是说,如果业务的处理时间大于超时时间的话,业务还没有执行完,资源就释放了,导致其他线程访问资源,导致不一致性,这里就需要加一个超时时间。

因为redis在主从集群里面的话,是将设置的值保存到一个redis服务里面,然后返回成功或者失败,然后在同步到从服务器,如果在设置的时候主服务器宕机了,那么就会收不到;这里redis提供了一个redisson,主服务器接受到消息之后设置成功之后不会立马返回true或者false,会先把主服务器的数据同步到从服务器,如果都成功了,才会返回true,否则返回false。

Changelog

Last Updated: View All Changelog
  • feat(wiki): hammeSpoon: 复制出来的文件需要重新生成永链

    On 3/27/25

求求了,快滚去学习!!!

求求了求求了,快去学习吧!

【题单】贪心算法

不知道方向的时候,可以多看看书,书会给你指明下一步该干什么,加油!