【并发】实现分布式锁的三种方式(主推Redisson)

什么时候用分布式锁

在项目中为保证共享变量的准确性,一般要加锁,一般想到的是synchronize,那什么时候要用分布式锁呢?我们在部署我们的服务的时候,可能会部署多台服务器,这样就会导致访问多台服务器的同一个接口,同时执行相同的逻辑,可能会同时更改数据,可能造成数据不对的问题,可以想象成不同系统中的多线程(比如A想把1改成2,B在A改后的基础上加1,成为3,结果它俩同时改,结果就成了2,这样结果就不对了),这个时候就用到分布式锁了。

分布式锁怎么用

分布式锁有三种实现方式

1、用Redisson实现分布式锁

一般是用了Redis,则选择用Redisson实现分布式锁
(1)引入Redisson的依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.6.5</version>
</dependency>

(2)添加配置文件

@Configuration
public class RedissonConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;

    @Bean
    public RedissonClient getRedisson(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://"+host+":"+port);
        return Redisson.create(config);
    }
}

(3)业务代码中使用

// 设置锁定资源名称 获取锁对象
RLock rLock = redissonClient.getLock("redisson:lock:key");
try {
     // 尝试加锁,最多等5秒,上锁以后10秒自动解锁
     rLock.tryLock(5,10,TimeUnit.SECONDS);
     // 业务操作代码
     }
 }catch (InterruptedException e){
     e.printStackTrace();
 }
 finally {
 	 // 释放锁
     rLock.unlock();
 }

我用了tryLock加锁,加锁还有多种方式

  // 普通用法
  rLock.lock();
  // 支持过期解锁功能,5秒钟以后自动解锁, 无需调用unlock方法手动解锁
  rLock.lock(5, TimeUnit.SECONDS);
  // 尝试加锁,最多等5秒,上锁以后10秒自动解锁
  rLock.tryLock(5,10,TimeUnit.SECONDS);
  ......

2、用Mysql的行锁实现分布式锁

在争抢锁的时候向数据库写一条记录,插入成功表示当前线程获取到了锁,插入失败表示当前锁被占用,一会儿接着抢,直到抢到或者超时为止。
为什么会有插入失败呢,因为Mysql支持行锁(InnoDB引擎),行锁的话,同一时间只能有一个线程只能操作一行数据,所以会有插入失败的情况,这也就保证了只会有一个线程获取到锁然后执行任务。

3、用Zookeeper的临时节点实现分布式锁

使用Zookeeper的临时节点实现分布式锁,前提是我们项目用了Zookeeper。
为什么能用Zookeeper实现分布式锁呢,是因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,如果节点删除,也会通知别人来请求创建节点。这也就保证了只会有一个线程获取到锁然后执行任务。

这三种实现方式,用Redisson实现的分布式锁是相对比较好的。

©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页