Springboot整合Redisson 锁

一、依赖

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

二、配置文件

spring:redis:database: 7host: 116.62.178.11port: 6379password: 1234qwer#  spring-boot 1.0默认 jedis;  spring-boot2.0 默认lettuce ,lettuce线程安全lettuce:pool:# 连接池中的最大空闲连接 默认8max-idle: 8# 连接池中的最小空闲连接 默认0min-idle: 500# 连接池最大连接数 默认8 ,负数表示没有限制max-active: 2000# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1max-wait: -1cache:type: redis

二、增加Configuration类

@Configuration
public class RedissonConfig {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Value("${spring.redis.password}")private String password;@Bean(destroyMethod = "shutdown")RedissonClient redissonClient() throws IOException {Config config = new Config();config.useSingleServer().setPassword(password).setAddress("redis://" + host + ":" + port).setDatabase(7);return Redisson.create(config);}
}

三、锁的使用

 @RequestMapping(value = "/redissonlocked", method = {RequestMethod.GET})public void redissonTest() {String key = String.format("data-mining:task_statistic:%d", System.currentTimeMillis());RLock rLock = redissonClient.getLock(key);try {// 尝试加锁,最多等待1秒,上锁以后10秒自动解锁,没有Watch Dog,10s后自动释放boolean res = rLock.tryLock(1, 10, TimeUnit.SECONDS);if (!res) {return new RuntimeException("请勿重复提交");}} finally {rLock.unlock();}}
private void redissonDoc() throws InterruptedException {//1. 普通的可重入锁RLock lock = redissonClient.getLock("generalLock");// 拿锁失败时会不停的重试// 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30slock.lock();// 尝试拿锁10s后停止重试,返回false// 具有Watch Dog 自动延期机制 默认续30sboolean res1 = lock.tryLock(10, TimeUnit.SECONDS);// 拿锁失败时会不停的重试// 没有Watch Dog ,10s后自动释放lock.lock(10, TimeUnit.SECONDS);// 尝试拿锁100s后停止重试,返回false// 没有Watch Dog ,10s后自动释放boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);//2. 公平锁 保证 Redisson 客户端线程将以其请求的顺序获得锁RLock fairLock = redissonClient.getFairLock("fairLock");//3. 读写锁 没错与JDK中ReentrantLock的读写锁效果一样RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock");readWriteLock.readLock().lock();readWriteLock.writeLock().lock();
}

读写锁

public class RedissionDemo {@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate RedisTemplate redisTemplate;/*** 读写锁 总结** 读锁又叫共享锁* 写锁又叫排他锁(互斥锁)* 读 + 读 相当于无锁,并发读,同时加锁成功* 写 + 写 阻塞状态* 写 + 读 等待写锁释放* 读 + 写 等待读锁完,才写,*/public String writeValue() {String str = "";RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("writeLock");RLock rLock = readWriteLock.writeLock();try {rLock.lock();str = UUID.randomUUID().toString();redisTemplate.opsForValue().set("uuid", str);Thread.sleep(30000);} catch (Exception e) {} finally {rLock.unlock();}return str;}/*** 读锁** @return*/public String readValue() {String str = "";RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("writeLock");RLock rLock = readWriteLock.readLock();rLock.lock();str = (String) redisTemplate.opsForValue().get("uuid");rLock.unlock();return str;}}

信号量

public class RedissionDemo {@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate RedisTemplate redisTemplate;/*** 信号量** @return*///停车方法@GetMapping("/park")public String park() throws InterruptedException {//这里是获取信号量的值,这个信号量的name一定要与你初始化的一致RSemaphore park = redissonClient.getSemaphore("park");//这里会将信号量里面的值-1,如果为0则一直等待,直到信号量>0park.acquire();//tryAcquire为非阻塞式等待//park.tryAcquire();return "ok";}public String go() throws InterruptedException {//这里是获取信号量的值,这个信号量的name一定要与你初始化的一致RSemaphore park = redissonClient.getSemaphore("park");//这里会将信号量里面的值+1,也就是释放信号量park.release();return "ok";}
}

闭锁

public class RedissionDemo {@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate RedisTemplate redisTemplate;/*** 闭锁,限流** @return* @throws InterruptedException*///锁门public String lockdoor() throws InterruptedException {RCountDownLatch door = redissonClient.getCountDownLatch("door");//设置一个班级有20个同学door.trySetCount(20);//需要等到20个同学全部离开,才锁门door.await();return "锁门了";}public String leave(Long id) throws InterruptedException {RCountDownLatch door = redissonClient.getCountDownLatch("door");//表示一个同学离开door.countDown();return "" + id + "号同学离开了";}
}

四、分布式秒杀

秒杀流程:

@Service
@Slf4j
public class DistributedSecKillBiz {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate RedissonClient redissonClient;/*** 分布式锁。唯一缺点 枷锁失效时间* 枷锁院子操作,* 解锁,删除锁也是原子操作 瑕疵没有续命** @return*/public String doKill() {String lock = UUID.randomUUID().toString();String goodsId = "10054";boolean flag = redisTemplate.opsForValue().setIfAbsent(goodsId, lock, 30, TimeUnit.SECONDS);if (flag) {// 获取锁成功try {Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);if (stock > 0) {redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);log.info("扣减库存成功,还剩:" + stock);}return "库存不足,该商品已抢购完!";} catch (Exception e) {} finally {String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(goodsId), lock);}}return doKill();}/*** 整合 redission* @return*/public String doKillDistributed() {String goodsId = "10054";RLock lock = redissonClient.getLock(upActivityKey() + SecKillConstant.LOCK + goodsId);// 获取锁成功try {//1 阻塞式等待,默认30秒时间//2 自动续期,如果业务超长,续上新的30秒,不用担心过期时间,锁自动删除掉//3 枷锁的业务运行完成,就不会给当前的锁自动续期,即使没有手动释放锁也会,30秒自动释放
//            lock.lock(30, TimeUnit.SECONDS); //不会自动续期需要注意lock.lock();Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);if (stock > 0) {redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);log.info("扣减库存成功,还剩:" + stock);}return "库存不足,该商品已抢购完!";} catch (Exception e) {} finally {lock.unlock();}return "fail";}/*** 获取活动** @return*/public ActivityBo upActivity() {return new ActivityBo("七夕活动", "SEVEN_ACTIVITY", new Date(), new Date());}/*** 活动公共key** @return*/public String upActivityKey() {return SecKillConstant.SEC_KILL + upActivity().getActivityKey() + ":";}
}

五、redis锁 单机版可用,分布式用Redisson

package com.yang.yimall.seckill.app.seckill.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/*** redis 锁 集群有瑕疵 不能 续命*/
@Service
public class RedisLock {@Autowiredprivate RedisTemplate redisTemplate;private String lockName = "lockName";private ThreadLocal<String> threadLocal = new ThreadLocal<>();public void lock(String lockName) {if (tryLock(lockName)) {return;}lock(lockName);}public void lock() {if (tryLock(lockName)) {return;}lock();}/*** 添加key 并且设置过期时间 原子操作** @param lockName* @return*/public boolean tryLock(String lockName) {String uuid = UUID.randomUUID().toString();threadLocal.set(uuid);return redisTemplate.opsForValue().setIfAbsent(lockName, uuid, 30, TimeUnit.SECONDS);}/*** 如果查询有key,就删除, 原子操作*/public void unlock() {String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList(lockName), threadLocal.get());}
}

使用

 public String doKillUp() {String goodsId = "10054";redisLock.lock(goodsId);// 获取锁成功try {Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);if (stock > 0) {redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);log.info("扣减库存成功,还剩:" + stock);}return "库存不足,该商品已抢购完!";} catch (Exception e) {} finally {redisLock.unlock();}return "库存不足,该商品已抢购完!";}

springboot 集成redission分布式锁相关推荐

  1. SpringBoot实战实现分布式锁一之重现多线程高并发场景

    实战前言:上篇博文我总体介绍了我这套视频课程:"SpringBoot实战实现分布式锁" 总体涉及的内容,从本篇文章开始,我将开始介绍其中涉及到的相关知识要点,感兴趣的小伙伴可以关注 ...

  2. spring定时任务(Scheduled)运行阻塞不执行/Redission分布式锁阻塞问题

    spring定时任务(Scheduled)运行阻塞不执行/Redission分布式锁阻塞问题 最近项目中发现一个bug,排查了很久,最后发现问题所在,在此记录一下. 问题描述: 项目运行一段时间后,c ...

  3. redis和redission分布式锁原理及区别

    redis和redission分布式锁原理及区别 我最近做租车项目,在处理分布式时用到分布式锁,我发现很多同事都在网上找分布式锁的资料,但是看的资料都不是很全,所以在这里我谈谈自己的分布式锁理解. 结 ...

  4. springboot(十二)-分布式锁(redis)

    什么是分布式锁? 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁.进程锁. 线程锁:主要用来给方法.代码块加锁.当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段.线程锁只在同一 ...

  5. SpringBoot 使用 Redis 分布式锁解决并发问题

    问题背景 现在的应用程序架构中,很多服务都是多副本运行,从而保证服务的稳定性.一个服务实例挂了,其他服务依旧可以接收请求.但是服务的多副本运行随之也会引来一些分布式问题,比如某个接口的处理逻辑是这样的 ...

  6. springboot整合Redis分布式锁最佳实践

    什么是分布式锁 在单机环境中,一般在多并发多线程场景下,出现多个线程去抢占一个资源,这个时候会出现线程同步问题,造成执行的结果没有达到预期.我们会用线程间加锁的方式,比如synchronized,lo ...

  7. SpringBoot笔记:SpringBoot集成MinIO分布式文件系统

    文章目录 搭建MinIO集群 SpringBoot集成 添加依赖 添加配置 获取MinioClient MinioUtils完整工具类 测试代码 搭建MinIO集群 首先搭建MinIO的分布式集群,集 ...

  8. springboot集成Apollo分布式配置

    安装Apollo服务 1.安装mysql 地址:https://www.cnblogs.com/xuaa/p/10782352.html 2.下载Apollo源码到本地 地址:https://gith ...

  9. SpringBoot整合redisson分布式锁

    1.为什么要使用分布式锁 在分布式场景下为了保证数据最终一致性.在单进程的系统中,存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步(lock-synchronized), ...

最新文章

  1. redis灵魂拷问:如何使用stream实现消息队列
  2. 嵌入式程序员应知道的0x10个基本问题
  3. 【Vegas原创】SQL case when 用法
  4. 【TYVJ】1359 - 收入计划(二分)
  5. 算法数据结构(一)-B树
  6. 微服务API设计的实践与思考总结
  7. Django从理论到实战(part7)--关于视图函数与URL映射
  8. matlab全安装多大_不理会其他,我只中意T20天正V2.0软件,激活安装教程在这里...
  9. 3d正方体旋转相册代码_3d旋转正方体的多种html和css制作方法和相关知识复习讲解
  10. url传递中文的解决方案总结
  11. 摩托罗拉G7系列发布:G7 Plus还有中国红配色
  12. 怎么样判断页面是否在iframe框架里
  13. 生成缩略图代码(转帖)
  14. 谷歌技术帮助美军方无人机识别更精准
  15. OpenCV cv.INTER_AREA和cv.INTER_CUBIC 还有cv.INTER_LINEAR
  16. 设置Node.js脚本开机自启动
  17. css找某个元素的下个子元素,使用CSS获取特定位置的子元素
  18. [ffmpeg][goav]ffmpeg代码例子pcmu重采样并转码aac格式
  19. 图文讲解 WiFi 驱动移植过程,很肝~
  20. 编译php为opcode,php 中间代码opcode

热门文章

  1. 部署IIS网站HTTPS访问
  2. 设置海思芯片MMZ内存、OS内存详解
  3. Python opencv 在图片上写字
  4. 抖音 K.O. 快手之后还能火多久?
  5. vivo计算机有没有弧度计算公式,x 23手机背面弧度大不大??
  6. 阿松嘚嘚嘚-数据库篇2-完美范式不完美
  7. 10款大数据处理编程语言
  8. C#窗体加标尺的两种方式及显现效果
  9. 《C++ Primer》读书笔记——第十三章_拷贝控制
  10. No property creategoryType found for type xxx! Did you mean ‘xxx‘?