Redis锁由来

首先我们说一下分布式出现之前的锁

进程锁:

控制某一系统中多个进程访问共享资源时候造成冲突,因为单个进程是有独立性的,进程与进程之间无法访问其他进程的资源,因此线程锁实现方式synchronized等无法完成。

线程锁:

线程锁是主要是给某一代码块加锁,当这个代码块加锁后,比如synchronized后,第二个线程进来就无法执行这一段代码。常用的还有给某一个全局变量加锁,因为全局变量如果不加锁的话,一旦多个线程进来,并发的情况下,这个变量的值就会造成混乱。常用的有threadLocal修饰全局变量。

随着分布式部署的出现,越来越多的问题开始涌现,比如之前的那些锁的问题,已经不再满足现在多个系统互相调用时候出现的变量共享了,这时候,分布式锁就应运而生。

这一节我们主要讲一下redis分布式锁,当然了分布式锁常用的还有zookeeper分布式锁,以后我们再讨论zk锁。

Redis分布式锁具体实现:

1. 引入jar包,maven依赖如下

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

2. Java类

/*** 基于redisson的实现的redis分布式锁* com.bjrhxq.platform.application.distributedlock.redis**/
public class RedisDistributedLock {private final static Logger logger = LoggerFactory.getLogger(RedisDistributedLock.class);/*** 加锁等待时间*/private Long lockWaitTime;/***自动解锁时间*/private Long autoReLockTime;/*** 时间单位 1 秒,2 分钟,3小时,4天*/private Integer timeUnit;/*** rediss客户端*/private RedissonClient redissonClient;private final static Long LOCKWAITTIME_NUM = 0L;//默认加锁等待时间(0秒)private final static Long AUTORELOCKTIME_NUM = 5L;//默认释放锁时间(5秒)private final static Integer TIMEUNIT_VALUE = 1;//单位默认值(秒)private RedisDistributedLock(){}public RedisDistributedLock(String redisServices,Long _lockWaitTime,Long _autoReLockTime){if (StringUtils.isBlank(redisServices)){logger.error("redisServices为空!请上传");throw new BzException("redisServices为空");}this.autoReLockTime = _autoReLockTime == null?AUTORELOCKTIME_NUM:_autoReLockTime;this.lockWaitTime = _lockWaitTime == null?LOCKWAITTIME_NUM:_lockWaitTime;this.timeUnit =TIMEUNIT_VALUE;redissonClient = RedissonUtils.getInstance().getRedisson(redisServices);}public RedisDistributedLock(String redisServices,Long _lockWaitTime,Long _autoReLockTime,Integer _timeUnit){if (StringUtils.isBlank(redisServices)){logger.error("redisServices为空!请上传");throw new BzException("redisServices为空");}this.autoReLockTime = _autoReLockTime == null?AUTORELOCKTIME_NUM:_autoReLockTime;this.lockWaitTime = _lockWaitTime == null?LOCKWAITTIME_NUM:_lockWaitTime;this.timeUnit =_timeUnit;redissonClient = RedissonUtils.getInstance().getRedisson(redisServices);}//程序一旦启用不能关闭redissonClient否则会报cannot be started once stopped 导致程序中断无法启动,该方法只用于测试使用关闭客户端与服务端连接public void closeReddisson(){redissonClient.shutdown();}/*** 获取锁* @param lockName*/public boolean getLock(String lockName){RLock rlock = redissonClient.getLock(lockName);try {return rlock.tryLock(lockWaitTime,autoReLockTime,exchangeTimeUnit(timeUnit));} catch (InterruptedException e) {return false;}}/*** 释放锁* @param lockName*/public void releaseLock(String lockName){RLock rlock = redissonClient.getLock(lockName);rlock.unlock();}private TimeUnit exchangeTimeUnit(int _timeUnit){switch (_timeUnit) {case 1:return TimeUnit.SECONDS;case 2:return TimeUnit.MINUTES;case 3:return TimeUnit.HOURS;case 4:return TimeUnit.DAYS;}return TimeUnit.SECONDS;}
}

3. 测试类

/*** src.test**/
public class TestRedissionShan {final String LOCK_KEY="TEST_123";public static void main(String[] args) {TestRedissionShan test1 = new TestRedissionShan();test1.testLock("test1");TestRedissionShan test2 = new TestRedissionShan();test2.testLock("test2");}public void testLock(String name){
//下面的三个地址以及端口可以参照上一篇文章redis集群,写入你配好的集群地址RedisDistributedLock redisDistributedLock = new RedisDistributedLock("192.168.122.32:9210,192.168.122.33:9211,192.168.122.34:9212",null,5L,1);
//第二个测试再将此段代码解除注释
// if ("test2".equals(name)){
// try {
// System.err.println(name+"准备睡眠6秒");
// Thread.sleep(6000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }boolean lock = redisDistributedLock.getLock(LOCK_KEY);System.out.println(name+"拿到锁了吗?"+lock+"---线程名字:"+Thread.currentThread().getName());if (lock){System.out.println(name+"拿到锁了准备操作。。。。。");System.out.println(name+"我自己测试还能不能加锁<"+redisDistributedLock.getLock(LOCK_KEY)+">");}else{System.err.println(name+"未拿到锁不操作。。。。。");}}}

测试结果:

est1拿到锁了吗?true---线程名字:main

test1拿到锁了准备操作。。。。。

test1我自己测试还能不能加锁<true>

test2拿到锁了吗?false---线程名字:main

test2未拿到锁不操作。。。。。

可见在test1拿到锁后,如果不释放,test2是没有办法对这个锁进行任何操作的

下面我们再测试下,将上面的那一段注掉的代码释放开(因为默认释放时间是5秒)

我们让test2线程等待6秒,正常情况下是可以再次对同一个锁进行操作的,因为test1过了5秒已经释放了锁

接下来看输出结果:

est1拿到锁了吗?true---线程名字:main

test1拿到锁了准备操作。。。。。

test1我自己测试还能不能加锁<true>

test2准备睡眠6秒

test2拿到锁了吗?true---线程名字:main

test2拿到锁了准备操作。。。。。

test2我自己测试还能不能加锁<true>

测试结果正如前面所说,这里需要注意下有个当前线程加完锁后,还可以对其进行加锁,我们不妨想一下,你自己加的锁,加完后你自己可以对其做任何操作,包括再次加锁(再次加锁我们只是测试,实际中并不会使用)

以上就是Redis分布式锁的一个实现方式,当然了,redis还有很多种实现方式,原生的不容易理解,这里我们选择了一种相对容易上手的。

(11)Redis------分布式锁的实现方式之一(基于Springboot项目搭建)相关推荐

  1. redis 分布式锁的实现方式

    情景如下: 我们有一批任务需要由多个分布式线程处理,每个任务都有一个taskId,为了保证每个任务只被执行一次,在工作线程执行任务之前,先获取该任务的锁,锁的key可以为taskId 方式1:set( ...

  2. Java版基于Redis分布式锁的实现方式

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

  3. Redis分布式锁 Spring Schedule实现任务调度

    一看到标题就知道,这一篇博客又是总结分布式工作环境中集群产生的问题,个人觉得分布式没有那么难以理解,可能也是自己见识比较浅,对我来说,分布式只是一种后端业务演进时的一种工作方式,而真正实现这种工作方式 ...

  4. redis setnx 分布式锁_手写Redis分布式锁

    分布式锁使用场景 现在的系统都是集群部署,每个服务都不是单节点的了.比如库存服务,可能部署到3台机器上分别命名为节点1,节点2,节点3.库存服务需要扣减库存,扣减库存肯定需要锁吧,如果使用Lock或者 ...

  5. getset原子性 redis_一文看透 Redis 分布式锁进化史(解读 + 缺陷分析)

    各个版本的Redis分布式锁 V1.0 V1.1 基于[GETSET] V2.0 基于[SETNX] V3.0 V3.1 分布式Redis锁:Redlock 总结 <Netty 实现原理与源码解 ...

  6. 一个项目部署多个节点会导致锁失效么_一文看透 Redis 分布式锁进化史(解读 + 缺陷分析)...

    各个版本的Redis分布式锁 V1.0 V1.1 基于[GETSET] V2.0 基于[SETNX] V3.0 V3.1 分布式Redis锁:Redlock 总结 <Netty 实现原理与源码解 ...

  7. 探讨Redis分布式锁解决优惠券拼抢问题

    一.什么是分布式锁 分布式锁是控制不同系统之间访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来确保数据一致性. 二.为什么需要分布式锁 ...

  8. 说一说redis分布式锁的几种实现及优缺点

    基于Jedis setnx.expire实现分布式锁(存在问题,作为错误示范) 先引入相关依赖(jedis 2.3.0后支持redis集群模式,2.4.2后支持jedisCluster多线程处理,2. ...

  9. 得物技术浅谈深入浅出的Redis分布式锁

    一.什么是分布式锁 1.1 分布式锁介绍 分布式锁是控制不同系统之间访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性. 1.2 ...

  10. Redis分布式锁一文全攻略

    分布式锁概念 分布式锁其实就是,控制分布式系统的不同进程共同访问共享资源的一种锁的实现.如果不同系统或同一个系统的不同主机去访问一个共享的临界资源,往往需要互斥来防止彼此干扰,以保证一致性. 分布式锁 ...

最新文章

  1. 比较ArrayList、LinkedList、Vector
  2. GitHub发福利:30多万元资源,学生可以免费用
  3. 织女的红线_JAVA
  4. emacs-w3m查看html帮助手册
  5. 英特尔+性能+linux,Linux 4.20内核在英特尔处理器上性能比Linux 4.19低,附原因解释...
  6. urlconnection.connect()和url.openconnection()的区别
  7. Exchange2007获取OWA邮箱容量的代码
  8. Android 四大组件学习之Service六
  9. python与财务报表分析_《财务报表分析》第八章 企业财务综合分析与业绩评价课后练习...
  10. 分享免费的主流电商平台商品图片批量下载方法
  11. 字节跳动的产品经理是怎么工作的?
  12. 胸怀——勇气——智慧
  13. 正则表达式生成器,测试器(附C#代码)
  14. WCF各种banding支持的类型
  15. class和Class的区别
  16. 这是不是你在找的【电销帮手】——人机耦合佳信静默机器人
  17. java之ResourceBundle类详细分析(全)
  18. 韩信点兵问题的c++解法【笔记】
  19. pvs-stdio ue4_使用PVS-Studio for C#在GitLab中分析合并请求
  20. windows终端连接虚拟机

热门文章

  1. java线程状态、新建状态、运行状态、阻塞状态、等待阻塞、同步阻塞、其他阻塞、死亡状态
  2. Spring搭建本地源码调试环境
  3. 字节码指令之操作数栈管理指令
  4. 全面理解ThreadLocal
  5. LeetCode--042--接雨水(java版)
  6. Js实现input上传图片并显示缩略图
  7. Liferay中页面的权限控制
  8. [译]Vue 2.0的变化(一)之基本API变化
  9. 调整数组使奇数全部都位于偶数前面
  10. iOS AutoLayout自动布局中级开发教程(2)-等宽等高等中心