读写锁、信号量、闭锁-分布式锁和同步器

参考文档:https://github.com/redisson/redisson/wiki/8.-分布式锁和同步器

读写锁


	//注入redisson
   @Autowired
    RedissonClient redisson;
	
	//注入redis
    @Autowired
    StringRedisTemplate redisTemplate;
    //没有引入依赖的请参照redis回顾  https://blog.csdn.net/qq_42604730/article/details/112727076引入依赖



	//保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁,独享锁)。读锁是一个共享锁
    //写锁没释放,读就必须等待
    //读+读:相当于无锁,并发读,只会在redis记录好,所有当前的读锁。他们都会同时加锁成功
    //写+读:等待写锁释放
    //写+写:阻塞方式,下一个写锁必须等待上一个写锁释放
    //读+写:有读锁。写也需要等待
    //总结:只要有写的存在,都必须等待


	//写方法
    @ResponseBody
    @GetMapping("/write")
    public String writeValue(){
   	 	//获取读写锁
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        String s="";
        //加写锁
        RLock rLock = lock.writeLock();//拿到写锁
        try {
            //1、改数据加写锁,读数据加读锁
            rLock.lock();
             s = UUID.randomUUID().toString();
            Thread.sleep(30000);//休眠30秒
            redisTemplate.opsForValue().set("writeValue",s);//给redis存入一个值
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();//释放写锁
        }
        return s;
    }



	//读方法
 	@ResponseBody
    @GetMapping("/read")
    public String readValue(){
    	//拿到读写锁
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");

        String s="";
     	//加读锁
        RLock rLock = lock.readLock();//拿到读锁
        rLock.lock();//加锁
        try {
	
            s = redisTemplate.opsForValue().get("writeValue");//获取redis中的值
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();//释放读锁
        }
        return s;
    }

测试:
1、在redis添加一个键值
在这里插入图片描述
调用请求读方法
在这里插入图片描述
调用请求写方法
在这里插入图片描述
写值成功,读值才能成功,写值一更改,读就必须等写锁释放。

信号量

例子: 车库停车,有3个车位,只要来一辆车,占用一个车位,走了一个释放一个车位,想停车要看车位够不够

 /**
     * 车库停车
     * 3车位
     * 信号量也可以用作分布式限流
     */

	//停车请求,获取一个车位
    @GetMapping("/park")
    @ResponseBody
    public String park() throws InterruptedException {
		
        RSemaphore park = redisson.getSemaphore("park");
//        park.acquire();//获取一个信号,获取一个值,占一个车位
//acquire()是阻塞式获取,相当于一定要获取车位
//park.tryAcquire()有车位就停,没有就算了,获取成功返回true否则返回false
        boolean b = park.tryAcquire();
        if (b){ 
            //执行业务
        }else {
            return "error";
        }
        return "ok=>"+b;
    }



//释放一个车位
@GetMapping("/go")
    @ResponseBody
    public String go() throws InterruptedException {

        RSemaphore park = redisson.getSemaphore("park");
        park.release();//释放一个车位

//        Semaphore semaphore=new Semaphore(5);
//        semaphore.release();
//        semaphore.acquire();
        return "ok";
    }

测试,在redis中添加键为park,值为3
在这里插入图片描述
发送停车请求,redis中的信号量-1
在这里插入图片描述
在这里插入图片描述
当信号为0时再次发送停车请求,提示error,表示位置已占满
在这里插入图片描述

在这里插入图片描述
当进行释放请求,释放车位时,信号量回来
在这里插入图片描述
在这里插入图片描述
一般用做限流操作

闭锁

/**
     * 放假,锁门
     * 1班没人了、2
     * 5个班全部走完,我们可以锁大门
     */
	
	//锁门方法
    @GetMapping("/lockDoor")
    @ResponseBody
    public String lockDoor() throws InterruptedException {
    	
        RCountDownLatch door = redisson.getCountDownLatch("door");
        //设置等待多少个班走完
        door.trySetCount(5);
        door.await();//等待闭锁都完成
        return "放假了...";
    }



//离开方法
	@GetMapping("/gogogo/{id}")
    public String gogogo(@PathVariable("id") Long id){
    	//获取闭锁
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.countDown();//计数减1
        return id+"班的人都走了...";
    }

调用锁门方法,一直在请求,因为是闭锁,有5个数,需要5个都走完
在这里插入图片描述
调用离开方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
走完之后,闭锁调用成功
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值