【大型电商项目开发】缓存-分布式锁-Redisson简洁&整合-lock锁-Redisson解决死锁-读写锁-闭锁-信号量-44

一:Redisson——完成分布式锁

1.简介

Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。充分 的利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中常用接口,为使用者 提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工 具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式 系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间 的协作。
官方文档:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95

2.导入redisson依赖——整合redisson作为分布式锁的框架

<!--使用redisson作为分布式锁,分布式对象等功能框架-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.0</version>
        </dependency>

3.配置redisson

1)新建MyRedissonConfig文件,配置redisson

package com.sysg.gulimail.product.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
public class MyRedissonConfig {
    /**
     * 所有对redisson的使用都是通过RedissonClient对象
     * @return
     * @throws IOException
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() throws IOException {
        //1.创建配置
        Config config = new Config();
        config.useSingleServer().setAddress(redis://127.0.0.1:6379");
        //2.根据config对象,创建出RedissonClient示例
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
}
  • 创建配置 Config config = new Config();
  • 使用单集群模式 config.useSingleServer().setAddress(127.0.0.1:6379");
  • 根据config对象,创建出RedissonClient示例 RedissonClient redissonClient = Redisson.create(config);
  • redis:// 安全连接

二:可重入锁——避免死锁问题

可重入锁:基于redis的redisson分布式。实现了java对象的lock接口。

1.代码实现

    @ResponseBody
    @GetMapping("/hello")
    public String hello(){
        //1.获取一把锁,只要锁名字一样,就是一把锁
        RLock lock = redisson.getLock("my-lock");
        //2.加锁
        lock.lock();//阻塞式等待,一直等,直到拿到锁,才会向下执行
        try {
            System.out.println("加锁成功,执行业务带代码。。"+Thread.currentThread().getId());
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //3.解锁
            System.out.println("释放锁。。。"+Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }
  • 获取一把锁:RLock lock = redisson.getLock("my-lock");只要锁名字一样,就是一把锁
  • 加锁:lock.lock();阻塞式等待,一直等,直到拿到锁,才会向下执行
  • 解锁:lock.unlock();
    redisson优势:——看门狗机制
    1.解决了锁的自动续期,如果业务超长,运行期间会自动续上新的30s。不用担心锁会过期会自动被删除。
    2.加锁的业务只要运行完成,不会自动续期,即使不手动解锁,默认30s以后会自动解锁。

2.使用lock方法加超时时间

lock.lock(10, TimeUnit.SECONDS);
Thread.sleep(30000);//业务执行时间
  • 在锁到了以后,不会自动续期
  • 自动解锁时间一定要大于业务的的执行时间
    结论:
    1.如果指定了超时时间,就发送给redis执行脚本,进行占锁,默认超时时间,就是指定的时间。
    2.如果未指定超时时间,我们就使用【LockWatchdogTimeout看门狗】的默认时间。
    3.只要占锁成功,就会启动定时任务,就会重新设置过期时间,新的时间就是看门狗的默认时间。
    4.只要业务没有执行完,就会每隔三分之一看门狗时间,自动续期。
    5.建议一般使用指定时间加锁,尽量可以将时间弄长一点。如果太长,就说明业务代码有问题。

三:读写锁(ReadWriteLock)

读写锁:分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。读锁和写锁是成对存在。写锁控制了读锁,只要写锁存在,读锁就要等待

1.测试读写锁

 @GetMapping("/write")
    @ResponseBody
    public String writeValue(){
        RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");
        RLock writeLock = readWriteLock.writeLock();
        String s = "";
        try {
            //1.改数据加写锁,读数据加读锁
            writeLock.lock();
            s = UUID.randomUUID().toString();
            Thread.sleep(30000);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock();
        }
        return s;
    }

    @GetMapping("/read")
    @ResponseBody
    public String readValue(){
        RReadWriteLock readWriteLock = redisson.getReadWriteLock("rw-lock");
        RLock readLock = readWriteLock.readLock();
        String readValue = "";
        readLock.lock();
        try {
            readLock.lock();
            readValue = redisTemplate.opsForValue().get("writeValue");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readLock.unlock();
        }
        return readValue;
    }

2.读写锁特点

读锁:读锁是一个共享锁,大家都可以用
写锁:写锁是排他锁(互斥锁,独享锁),同一时间只能有一个存在
1)写锁+读锁

  • 1.改数据加写锁,读数据加读锁
  • 2.保证一定可以读取到最新数据,修改期间,写锁是排他锁(互斥锁,独享锁),同一时间只能有一个存在。读锁是一个共享锁,大家都可以用
  • 3.写锁没释放,读锁必须等待

2)读锁+读锁

  • 相当于无锁,并发读,只会在redis中记录好所有当前的读锁,并且同时加锁成功

3)写锁+写锁

  • 阻塞方式

4)读锁+写锁

  • 有读锁,写锁也需要等待。只要有写的存在,必须等待。

四:闭锁——等待其他所有线程执行完毕才会释放

举例:放假,锁门。必须等所有学生走了以后才可以锁门。

1.代码实现

 /**
     * 放假,锁门。必须等所有学生走了以后才可以锁门。
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/lockDoor")
    @ResponseBody
    public String lockDoor() throws InterruptedException{
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.trySetCount(5);
        door.await(); //等待闭锁都完成
        return "放假了。。。";
    }
    @GetMapping("/gogogo/{id}")
    @ResponseBody
    public String gogogo(@PathVariable("id") Long id){
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.countDown();//计数减一
        return id + "班级的人都走了";
    }

五:分布式的信号量(Semaphore)——用来实现分布式限流

举例:车库停车,三个车位,来一辆占用一个车位,走一辆释放一个车位,当车的时候,看车位够不够

1.代码实现

 /**
     * 车库停车,三个车位,来一辆占用一个车位,走一辆释放一个车位,当车的时候,看车位够不够
     * @return
     */
    @GetMapping("/park")
    @ResponseBody
    public String park() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("name");
        //相当于占一个车位
        //park.acquire();//阻塞方法,获取成功才返回,否则一直调用
        boolean b = park.tryAcquire();
        if (b) {
            //执行复杂业务
            return "ok";
        } else {
            return "流量过大,请等待";
        }
    }

    @GetMapping("/go")
    @ResponseBody
    public String go() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("name");
        //相当于释放一个车位
        park.release();
        return "ok";
    }
  • 可以用来实现分布式限流服务,获取到信号量就可以访问,获取不到就等待。
  • tryAcquire能停就停,停不了就走,尝试获取
  • acquire会一直等待,直到等到为止
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随意石光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值