redis分布式锁java代码_基于redis实现分布式锁
“ 在上一篇文章中介绍了动态配置定时任务,其中的原理跟spring 定时任务注解@Scheduled一样的,都是通过线程池和定义执行时间来控制。来思考一个问题,如果我们的定时任务在分布式微服务里面呢?在分布式微服务里面一个微服务肯定可以有多个实例的,在上一篇文章当中配置的定时任务就会有可能存在多个,显然定时任务被多次执行并不是我们想要的结果,这个时候我们的分布式锁机制就出现了!”
(分布式锁有很多实现方式,以前我们都是使用synchronized来处理并发请求,虽然也支持分布式,但是总有一些业务不适合,比如秒杀系统的多个商品同时开启秒杀,同一时刻只能完成一件商品的减库存操作,这样就造成了系统的性能瓶颈,也不符合秒杀系统的设计思想。由于 synchronized 无法做到细粒度的控制,从而引进了分布式锁,分布式锁能够完成 synchronized 无法做到的点。下面我们要介绍的是基于redis的实现方式)。
01
—
引入redis依赖
引入springboot官方的redis依赖。
引入一个hutool工具包的依赖,功能很全的一个java工具包,强烈推荐使用。
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-data-redisartifactId>dependency><dependency> <groupId>cn.hutoolgroupId> <artifactId>hutool-allartifactId> <version>5.3.2version>dependency>
02
—
基于redis实现
怎么使用redis实现呢,先来看下redis的两个命令。
setnx:如果key不存在就跟set一样的作用,如果key存在则什么都不做
getandset:返回上一次的value,并设置新的value
import cn.hutool.core.util.StrUtil;import cn.hutool.log.StaticLog;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;/** * redis分布式锁 * * @author zhongxiaojian * @date 2020/4/17 **/@Componentpublic class LockUtil { @Autowired private StringRedisTemplate redisTemplate; /** * 加锁 * * @param key 主键 * @param value 当前时间+超时时间 * @return true or false */ public boolean lock(String key, String value) { Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, value); if (lock != null && lock) { return true; } String currentValue = redisTemplate.opsForValue().get(key); //如果锁过期 if (!StrUtil.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) { String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if (StrUtil.isBlank(oldValue) || (!StrUtil.isEmpty(oldValue) && oldValue.equals(currentValue))) { return true; } } return false; } /** * 解锁 * * @param key 主键 * @param value 当前时间+超时时间 */ public void unlock(String key, String value) { try { String currentValue = redisTemplate.opsForValue().get(key); if (!StrUtil.isEmpty(currentValue) && currentValue.equals(value)) { redisTemplate.opsForValue().getOperations().delete(key); } } catch (Exception e) { StaticLog.error("redis分布式锁解锁异常,{}", e.getMessage()); } }}
在上一篇文章当中的代码中使用
public class ScheduleTask implements Runnable { private static final int TIMEOUT = 30000; private String id; private TaskService service; private String keyword; private LockUtil lockUtil; public String getId() { return id; } /** * @param id 任务ID * @param service 业务类 * @param keyword 关键字参数 */ public ScheduleTask(String id, TaskService service,LockUtil lockUtil, String keyword) { this.id = id; this.service = service; this.lockUtil = lockUtil; this.keyword = keyword; } @Override public void run() { String currentTime = DateUtil.now(); long time = System.currentTimeMillis() + TIMEOUT; if (lockUtil.lock(id, String.valueOf(time))) { System.out.println("ScheduleTask start taskId: " + this.id + " time: " + currentTime); try { service.work(keyword); } catch (Exception e) { StaticLog.error(e.getMessage()); } finally { lockUtil.unlock(id, String.valueOf(time)); } } }}
03
—
秒杀系统下的应用
这里我们来解释一下为何在lock方法当中加上 “//如果锁过期” 后面的代码,我们以商品秒杀系统举例比较好理解。
假如我们不加上这段代码,在加锁之后的业务流程抛出了一个异常,且这个异常我们没有捕获并处理,那么我们接下来的解锁操作是不会执行的,这个时候我们的锁就变成了死锁,我们就可以使用getandset命令来进行解锁,举个?:
现有B商品在参加秒杀活动,假设一个购买B商品的线程发生了死锁,此时currentValue = 1,这个时候购买B商品的两个线程同时调用了lock方法,且value都等于2,同时这两个线程都进入了锁过期的判断"if (!StringUtils.isEmpty(currentValue)&& Long.parseLong(currentValue)
以上,就是我们使用redis实现了分布式锁。
如果你觉得小编写的对你有用的话就扶贫一下吧,哈哈哈
redis分布式锁java代码_基于redis实现分布式锁相关推荐
- 基于redis购物车java代码_基于redis实现购物车基本功能
1.准备工作: 数据库表设计 (yj_product_specification:商品规格表,用户表,商品表等 {没有规格表,只有规格值表,}), 测试工具:POSTMAN redis客户端: ...
- redis缓存原理与实现_基于Redis实现范围查询的IP库缓存设计方案
点击上方"码农沉思录" 发现更多精彩我先说下结果.我现在还不敢放线上去测,这是本地测的数据,我4g内存的电脑本地开redis,一次都没写完过全部数据,都是写一半后不是redis挂 ...
- redis过期监听性能_基于Redis的延迟处理
延迟处理是一个非常常用的一个功能; 例如, 下单成功后,在30分钟内没有支付,自动取消订单; 延迟队列便是延迟处理中最常见的实现方式; 先一起看下JDK中延迟队列是如何实现的. JUC的DelayQu ...
- 成绩查询系统源java代码_基于jsp的成绩查询系统-JavaEE实现成绩查询系统 - java项目源码...
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的成绩查询系统, 该项目可用各类java课程设计大作业中, 成绩查询系统的系统架构分为前后台两部分, 最终实现在线上 ...
- 运动会成绩管理java代码_基于jsp的运动会成绩管理-JavaEE实现运动会成绩管理 - java项目源码...
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的运动会成绩管理, 该项目可用各类java课程设计大作业中, 运动会成绩管理的系统架构分为前后台两部分, 最终实现在 ...
- 审批流程java 代码_基于jsp的企业流程审批系统-JavaEE实现企业流程审批系统 - java项目源码...
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的企业流程审批系统, 该项目可用各类java课程设计大作业中, 企业流程审批系统的系统架构分为前后台两部分, 最终实 ...
- 二维几何变换java代码_基于Batik的SVG应用: 关于几何变换
本文是作者在 SVGGIS 系统的开发实践过程中关于 SVG 坐标转换的总结.在描述 SVG 坐标变换原理的同时,使用 Apache Batik 项目实现了相关例子. SVG 是一种用 xml 语言来 ...
- 电子招投标java代码_基于jsp的招投标业务管理-JavaEE实现招投标业务管理 - java项目源码...
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的招投标业务管理, 该项目可用各类java课程设计大作业中, 招投标业务管理的系统架构分为前后台两部分, 最终实现在 ...
- 医院医生评价的java代码_基于JAVA的医院信息查询接口调用代码实例
基于JAVA的医院信息查询接口调用代码实例 import java.io.BufferedReader; import java.io.DataOutputStream; import java.io ...
最新文章
- 倒计时 | 7.24 阿里云 Serverless Developer Meetup 杭州站报名火热进行中!
- Spark - About trend of ERP topic - serie 2employee
- 定了!10 月 8 日!Jupyter Notebook 原生支持将正式来到 VS Code!
- mysql触发器对同一张表做操作_mysql的触发器同数据库 多表的数据操作
- MySQL内存及虚拟内存优化设置
- php+mysql数据库语法错误_求教:PHP+MYSQL制作用户登录系统问题,总是提示数据库查询语句语法不对。$sql=mysql_query(。。。)这行...
- Excel VBA教程之如何在功能区中显示 Excel 开发人员选项卡,启用vba(教程含源码)
- php工商亮照添加代码,市场监管总局电子营业执照亮照系统上线
- Linux 字符设备驱动及一些简单的Linux知识
- AxureShare太慢?尝试在内网架设Axure共享吧!
- 微信卡券开发具体的步骤,不会踩坑
- PS魔棒工具提示不能完成请求,因为程序错误和不能完成请求,因为没有足够内存以及内存不能为read的处理
- 基于gmapping的激光slam导航
- 计算机硬件和系统重装,重装系统对电脑有什么影响【图文】
- Unity3D研究院之静态自动检查代码缺陷与隐患
- 2019 Multi-University Training Contest 2:Beauty Of Unimodal Sequence(DP + 贪心构造)
- python编程else是什么意思_Python 中的 else详解
- Vue从入门到放弃(一)——指令篇
- 初识阿里云(云计算)--发展历程和技术架构、地域和可用区
- js中each的用法
热门文章
- 如何使用js动态显示或隐藏DIV
- 验证软件需求正确性的四个角度
- 数据结构与算法--10.利益最大值
- 启动django服务器报错raise errorclass(errno, errval) django.db.utils.InternalError
- java byte md5_Java开发网 - byte[]按自定义编码转换成String(MD5)
- 【机器学习】梯度下降原理
- E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用) E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-front
- epoll边缘触发_C++回声服务器_9-epoll边缘触发模式版本服务器
- 301缓存重定向?301 Moved Permanently (from disk cache)
- Unity 之 如何删除Unity项目里面没用的东西??