其他分享
首页 > 其他分享> > 分布式锁

分布式锁

作者:互联网

1、加锁解决缓存击穿问题

1)本地锁: 使用同步代码块

public Map<String,List<Catalog2Vo>> getCatalogJsonFromDb() {
    //只要是同一把锁,就能锁住使用这个锁的所有线程
    //synchronized (this)  SpringBoot项目中所有组件在容器中都是单例的
    synchronized (this){
        //得到锁之后,需要去缓存中查询一次,如果没有,才继续查询数据库
        String result = redisTemplate.opsForValue().get("xxxx");
        if(StringUtils.isNotBlank(result )){
            return result;
        }
       //查询数据库,返回结果
       return getResuleFromDb();
    }
}

 

2)本地锁在分部式情况下出现的问题

每个本地锁只能锁住当前项目请求过来的10000个请求,多个项目的情况下,依旧会查询多次数据库

0

 

2、分布式锁的原理和使用

1)分布式锁出现的问题

死锁:setnx占好了位,业务代码异常或者程序在页面过程中宕机,没有执行删除逻辑,这就造成了死锁问题

解决:设置锁的自动过期,即使没有删除也会自动删除

 

3、Redisson的使用

整合Redisson作为分布式锁

1)引入依赖

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

 

2)配置

/**
 * @author houChen
 * @date 2021/10/31 9:37
 * @Description: Redisson的配置类
 */
@Configuration
public class MyRedissonConfig {
    /**
     *  所有对Redisson的使用都是通过RedissonClient对象
     */
    @Bean
    public RedissonClient redisson(){
        //1、创建配置
        Config config = new Config();
        config.useSingleServer().setAddress("121.40.182.123:6379");
        //2、创建RedissonClient
        return Redisson.create(config);
    }
}

 

3)测试

mylock.lock() 是阻塞式的,若某个请求没有获取到锁,则一直阻塞在该处。

@ResponseBody
@GetMapping("/hello")
public String hello(){
    //1、获取一把锁,只要锁名一样,就是同一把锁
    RLock mylock = redisson.getLock("mylock");
    //2、加锁
    mylock.lock();
    try{
        System.out.println("加锁成功,正在执行业务......"+ Thread.currentThread().getId());
        Thread.sleep(30000);
    }catch (Exception e){

    }finally {
        System.out.println("释放锁" + Thread.currentThread().getId());
        mylock.unlock();
    }
    return  "hello";
}

0

 

4)一些问题

当加锁后,程序闪退了,没有执行解锁代码,会不会造成死锁?

不会,因为当锁没有续期时,超过30秒回自动删除

1)锁的自动续期,如果业务超长,运行期间会自动给锁续上30秒。不用担心业务时间长,锁自动过期被删除

2)加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30秒后自动删除

mylock.lock(10, TimeUnit.SECONDS); 10秒后会自动解锁,但是不会续期,所以解锁的时间一定要大于业务执行的时间

1、如果我们传递了锁的超时时间,就发送指令给redis脚本,进行占锁,默认超时就是我们指定的时间

2、如果我们未指定锁的超时时间,就使用30*1000 【LockWatchOutTimeOut看门狗的默认时间】

只要占领成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10秒自动 续期

 

4、Redisson 读写锁

 

5、Redisson 闭锁

/**
 *  闭锁演示
 *
 *  5个班的人都走完了,才能锁大门
 */
@GetMapping("/lockDoor")
@ResponseBody
public String lockDoor() throws InterruptedException {
    RCountDownLatch door = redisson.getCountDownLatch("door");
    door.trySetCount(5);
    door.await(); //等待闭锁都完成
    return  "放假了";
}

@GetMapping
@ResponseBody
public String gogogo(@PathVariable("id") Long id){
    RCountDownLatch door = redisson.getCountDownLatch("door");
    door.countDown(); // 计数减1
    return id + "班的人走了";
}

0

 

6、Redisson 分布式信号量

/**
 * 分布式信号量测试
 * 车位停车   3车位
   当车位为0时,停车操作将会阻塞
 *
 * 可以用来做分布式限流
 */
@GetMapping("/park")
@ResponseBody
public String park() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore("park");
    park.acquire();  //获取一个信号(占一个车位)
    return "ok";
}

@GetMapping("/go")
@ResponseBody
public String go() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore("park");
    park.release();  //获取一个信号
    return "go 车开走啦....";
}

标签:redisson,return,park,Redisson,door,public,分布式
来源: https://www.cnblogs.com/houchen/p/15616649.html