在上一篇文章中介绍了动态配置定时任务,其中的原理跟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实现分布式锁相关推荐

  1. 基于redis购物车java代码_基于redis实现购物车基本功能

    1.准备工作: 数据库表设计 (yj_product_specification:商品规格表,用户表,商品表等     {没有规格表,只有规格值表,}), 测试工具:POSTMAN redis客户端: ...

  2. redis缓存原理与实现_基于Redis实现范围查询的IP库缓存设计方案

    点击上方"码农沉思录"  发现更多精彩我先说下结果.我现在还不敢放线上去测,这是本地测的数据,我4g内存的电脑本地开redis,一次都没写完过全部数据,都是写一半后不是redis挂 ...

  3. redis过期监听性能_基于Redis的延迟处理

    延迟处理是一个非常常用的一个功能; 例如, 下单成功后,在30分钟内没有支付,自动取消订单; 延迟队列便是延迟处理中最常见的实现方式; 先一起看下JDK中延迟队列是如何实现的. JUC的DelayQu ...

  4. 成绩查询系统源java代码_基于jsp的成绩查询系统-JavaEE实现成绩查询系统 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的成绩查询系统, 该项目可用各类java课程设计大作业中, 成绩查询系统的系统架构分为前后台两部分, 最终实现在线上 ...

  5. 运动会成绩管理java代码_基于jsp的运动会成绩管理-JavaEE实现运动会成绩管理 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的运动会成绩管理, 该项目可用各类java课程设计大作业中, 运动会成绩管理的系统架构分为前后台两部分, 最终实现在 ...

  6. 审批流程java 代码_基于jsp的企业流程审批系统-JavaEE实现企业流程审批系统 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的企业流程审批系统, 该项目可用各类java课程设计大作业中, 企业流程审批系统的系统架构分为前后台两部分, 最终实 ...

  7. 二维几何变换java代码_基于Batik的SVG应用: 关于几何变换

    本文是作者在 SVGGIS 系统的开发实践过程中关于 SVG 坐标转换的总结.在描述 SVG 坐标变换原理的同时,使用 Apache Batik 项目实现了相关例子. SVG 是一种用 xml 语言来 ...

  8. 电子招投标java代码_基于jsp的招投标业务管理-JavaEE实现招投标业务管理 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的招投标业务管理, 该项目可用各类java课程设计大作业中, 招投标业务管理的系统架构分为前后台两部分, 最终实现在 ...

  9. 医院医生评价的java代码_基于JAVA的医院信息查询接口调用代码实例

    基于JAVA的医院信息查询接口调用代码实例 import java.io.BufferedReader; import java.io.DataOutputStream; import java.io ...

最新文章

  1. 倒计时 | 7.24 阿里云 Serverless Developer Meetup 杭州站报名火热进行中!
  2. Spark - About trend of ERP topic - serie 2employee
  3. 定了!10 月 8 日!Jupyter Notebook 原生支持将正式来到 VS Code!
  4. mysql触发器对同一张表做操作_mysql的触发器同数据库 多表的数据操作
  5. MySQL内存及虚拟内存优化设置
  6. php+mysql数据库语法错误_求教:PHP+MYSQL制作用户登录系统问题,总是提示数据库查询语句语法不对。$sql=mysql_query(。。。)这行...
  7. Excel VBA教程之如何在功能区中显示 Excel 开发人员选项卡,启用vba(教程含源码)
  8. php工商亮照添加代码,市场监管总局电子营业执照亮照系统上线
  9. Linux 字符设备驱动及一些简单的Linux知识
  10. AxureShare太慢?尝试在内网架设Axure共享吧!
  11. 微信卡券开发具体的步骤,不会踩坑
  12. PS魔棒工具提示不能完成请求,因为程序错误和不能完成请求,因为没有足够内存以及内存不能为read的处理
  13. 基于gmapping的激光slam导航
  14. 计算机硬件和系统重装,重装系统对电脑有什么影响【图文】
  15. Unity3D研究院之静态自动检查代码缺陷与隐患
  16. 2019 Multi-University Training Contest 2:Beauty Of Unimodal Sequence(DP + 贪心构造)
  17. python编程else是什么意思_Python 中的 else详解
  18. Vue从入门到放弃(一)——指令篇
  19. 初识阿里云(云计算)--发展历程和技术架构、地域和可用区
  20. js中each的用法

热门文章

  1. 如何使用js动态显示或隐藏DIV
  2. 验证软件需求正确性的四个角度
  3. 数据结构与算法--10.利益最大值
  4. 启动django服务器报错raise errorclass(errno, errval) django.db.utils.InternalError
  5. java byte md5_Java开发网 - byte[]按自定义编码转换成String(MD5)
  6. 【机器学习】梯度下降原理
  7. E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用) E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-front
  8. epoll边缘触发_C++回声服务器_9-epoll边缘触发模式版本服务器
  9. 301缓存重定向?301 Moved Permanently (from disk cache)
  10. Unity 之 如何删除Unity项目里面没用的东西??