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实现了分布式锁。

如果你觉得小编写的对你有用的话就扶贫一下吧,哈哈哈

9f0a9350f59c9da7442180372473a988.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数值字符串

加粗样式 数值与字符串 受限于电脑内存 数字 int float 布尔 none 列表list:l[1,2,3] l[1]2 字典表dict:d{‘name’;‘tom’,‘age’:20} d.get(‘name’) d[‘name’] 元组t(1,2,3,4) 元组与列表区别&#xff1a;列表可以改变相应下标数据&#xff0c;元组不行。 数值&#x…

C语言写个贪吃蛇游戏

贪吃蛇是个非常经典的游戏&#xff0c;用C语言来实现也是一个好玩的事情。这个游戏我写完后放在知乎&#xff0c;竟然点赞的人数超级多。我觉得大家喜欢&#xff0c;一个方面是因为写得简单&#xff0c;大家都能看得懂&#xff0c;一个可扩展性还是非常强的。我试了说一下这个代…

seir模型matlab_疫情专题 | 传染病的经典数学模型

在此次新冠肺炎疫情防控过程中&#xff0c;对疫情发展趋势的科学预测显得尤为重要。而这背后&#xff0c;离不开对传染病传播规律的建模。今天&#xff0c;小编就带各位数学学子们来了解一下传染病的四大经典数学模型&#xff1a;SI/SIS/SIR/SEIR。其中用到了许多微分方程的知识…

vlh 标签详解

1.vlh:root root标签做为所有vlh标签的根标签. 1)value 在给定的范围内&#xff0c;包含在ValueList或list的变量名. List的实例自动被DefaultListBackedValueList包装在ValueList中 2)id 如果有多个表被包含在一个request中&#xff0c;ID属性能区分每个表。id被追加到所…

ubuntu电脑安装硬盘

最近在做安卓开发&#xff0c;一套RK3399的安卓代码&#xff0c;解压编译后占用170多G的硬盘。所以呢&#xff0c;原来1T大小的硬盘&#xff0c;很快就沾满了&#xff0c;然后我赶紧给北京总部申请买了一个新的硬盘。现在的台式电脑都是用的SATA硬盘接口&#xff0c;我赶紧就上…

python 制作抽奖箱_用Excel函数制作抽奖箱

话说各在公司每年的年会上&#xff0c;或者平时的一些分组活动上&#xff0c;又或者是某个内部组织的业务竞赛上……偶尔会遇到抽奖或抽签的环节&#xff0c;例如你的公司开展了一个实操的业务竞赛&#xff0c;一共80道题目&#xff0c;参赛人员要随机抽取题目然后做答。好的&a…

字典表

字典表 &#xff1a; dict 声明 键;值dict(键值) 操作 获取d.get(键‘默认值) 合并d.update(d2) 键值emp.items 菜单emp.keys 效果emp.values得到视图 遍历打印for x in emp.keys 支持嵌套 由于哈希算法导致顺序混乱可以将方法转换为列表&#xff0c;在排序 方法二 全局函…

Sql Server常用函数及技巧

使用Sql Server好长时间了&#xff0c;今天特别想总结一下&#xff0c;算是回顾吧&#xff01; 总结&#xff1a; 其实很多技巧&#xff0c;都是基于SQL Server自带的System Views&#xff0c;System Stored Procedures&#xff0c;System Functions (常用函数都在在里面)。 常…

十分钟让你明白AIDL

前言我在[003]AIDL是什么中介绍的AIDL&#xff0c;但是好像还有朋友不明白问我&#xff0c;那我就来写一个终极版的文章&#xff0c;让你十分钟彻底明白AIDL&#xff0c;以下代码全为手写。目标Server进程注册一个Binder服务到SM&#xff0c;该Binder服务提供两个接口&#xff…

表达式

表达式与分支 语句 分割文档main spilit 风格pep8 赋值 序列赋值 列表切割法 扩展序列解包赋值 *获取剩余 多目标赋值 数字256为界以内指向同对象 以外就不同 字符串3个 列表属于引用类型 不要共同引用两种方法 参数化赋值 列表也可以进行参数化赋值 表达式 函数 方法…

Linux下故障分析方法

1、背景有时候会遇到一些疑难杂症&#xff0c;并且监控插件并不能一眼立马发现问题的根源。这时候就需要登录服务器进一步深入分析问题的根源。那么分析问题需要有一定的技术经验积累&#xff0c;并且有些问题涉及到的领域非常广&#xff0c;才能定位到问题。所以&#xff0c;分…

TEXT宏

TEXT宏是windows程序设计中经常遇到的宏&#xff0c;定义在 <winnt.h>中 TCHAR *P TEXT("this is a const string"); 如果使用UNICODE字符集&#xff0c;则TEXT&#xff08;“....”&#xff09; &#xff0c;相当于 L"....." &#xff1b; 如果使…

作业题

import random fopen(‘data.txt’,‘w’) for i in range(10000): f.write(str(random.randint(1,100))) f.write(’\n’) f.seek(0) print(f.read()) f.close f.seek()函数 移动文件中n个操作 正为向结束方向 enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符…

即将放弃python的app_python放弃之 模块和包

importprint(frrom the my_module.py)money1000def rend1():print(my_my_module->reand1->money,money)def rend2():print(my_module->read2 calling read1)read1()def change():global moneymoney0模块可以包含可执行语句和函数的定义&#xff0c;这些语句的目的是初…

ubuntu 安装gitlab

gitlab 类似github&#xff0c;可以用来管理代码。当然除了他们两个还有很多代码管理的工具&#xff0c;国内的也有。我这篇文章就只讲gitlab的安装过程。但是gitlab并不是轻量级的东西&#xff0c;占用大概4~8G的内存&#xff0c;特别是merge的代码比较多的时候&#xff0c;占…

一些常用的linux命令(2)

参考&#xff1a;http://www.cnblogs.com/laov/p/3541414.html 系统管理命令 stat 显示指定文件的详细信息&#xff0c;比ls更详细 who 显示在线登陆用户 whoami 显示当前操作用户 hostname 显示主机名 uname 显示系统信…

迭代

迭代 文章目录迭代内置可迭代对象 range&#xff08;&#xff09;内置函数使用 map&#xff08;函数加对象&#xff09;函数定义与参数定义传参作用域函数参数传值可迭代对象支持迭代协议 遍历循环 因为 迭代协议 方法—next—&#xff08;&#xff09;函数next消耗内存小所占空…

python os renames_Python3 os.renames() 方法

概述os.renames() 方法用于递归重命名目录或文件。类似rename()。语法renames()方法语法格式如下&#xff1a;os.renames(old, new)参数old -- 要重命名的目录new --文件或目录的新名字。甚至可以是包含在目录中的文件&#xff0c;或者完整的目录树。返回值该方法没有返回值实例…

普通人的节奏

在立春当夜&#xff0c;这南方城市的上空响起了2020年的第一声春雷&#xff0c;大家都期待着这一声霹雳除去一切霉噩&#xff0c;带来万象更新。之后的天气逐渐变好&#xff0c;近日来更是风和日丽。前日&#xff0c;去采购食品和日用品&#xff0c;久不出门&#xff0c;趁好天…

DDD领域模型自动生成?

我不想写代码&#xff0c;只想通过界面配置一下就能自动生成代码多好&#xff0c;如果界面也能自动生成&#xff0c;那就更好了转载于:https://www.cnblogs.com/PerfectBeauty/p/7351849.html