转:https://blog.csdn.net/forezp/article/details/70305336

之前写过一篇文章《如何在springcloud分布式系统中实现分布式锁?》(https://blog.csdn.net/forezp/article/details/68957681),由于自己仅仅是阅读了相关的书籍,和查阅了相关的资料,就认为那样的是可行的。那篇文章实现的大概思路是用setNx命令和setEx配合使用。 setNx是一个耗时操作,因为它需要查询这个键是否存在,就算redis的百万的qps,在高并发的场景下,这种操作也是有问题的。关于redis实现分布式锁,redis官方推荐使用redlock。

一、redlock简介

在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。实现高效的分布式锁有三个属性需要考虑:

1、安全属性:互斥,不管什么时候,只有一个客户端持有锁
2、效率属性A:不会死锁
3、效率属性B:容错,只要大多数redis节点能够正常工作,客户端端都能获取和释放锁。

Redlock是redis官方提出的实现分布式锁管理器的算法。这个算法会比一般的普通方法更加安全可靠。关于这个算法的讨论可以看下官方文档(https://github.com/antirez/redis-doc/blob/master/topics/distlock.md)。

二、怎么用java使用 redlock

在pom文件引入redis和redisson依赖:

<!-- redis-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson-->
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.3.2</version>
</dependency>

AquiredLockWorker接口类,,主要是用于获取锁后需要处理的逻辑:

/*** Created by fangzhipeng on 2017/4/5.* 获取锁后需要处理的逻辑*/
public interface AquiredLockWorker<T> {T invokeAfterLockAquire() throws Exception;
}

DistributedLocker 获取锁管理类:

/*** Created by fangzhipeng on 2017/4/5.* 获取锁管理类*/
public interface DistributedLocker {/*** 获取锁* @param resourceName  锁的名称* @param worker 获取锁后的处理类* @param <T>* @return 处理完具体的业务逻辑要返回的数据* @throws UnableToAquireLockException* @throws Exception*/<T> T lock(String resourceName, AquiredLockWorker<T> worker) throws UnableToAquireLockException, Exception;<T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception;}

UnableToAquireLockException ,不能获取锁的异常类:

/*** Created by fangzhipeng on 2017/4/5.* 异常类*/
public class UnableToAquireLockException extends RuntimeException {public UnableToAquireLockException() {}public UnableToAquireLockException(String message) {super(message);}public UnableToAquireLockException(String message, Throwable cause) {super(message, cause);}
}

RedissonConnector 连接类:

/*** Created by fangzhipeng on 2017/4/5.* 获取RedissonClient连接类*/
@Component
public class RedissonConnector {RedissonClient redisson;@PostConstructpublic void init(){redisson = Redisson.create();}public RedissonClient getClient(){return redisson;}
}

RedisLocker 类,实现了DistributedLocker:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;/*** Created by fangzhipeng on 2017/4/5.*/
@Component
public class RedisLocker  implements DistributedLocker{private final static String LOCKER_PREFIX = "lock:";@AutowiredRedissonConnector redissonConnector;@Overridepublic <T> T lock(String resourceName, AquiredLockWorker<T> worker) throws InterruptedException, UnableToAquireLockException, Exception {return lock(resourceName, worker, 100);}@Overridepublic <T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception {RedissonClient redisson= redissonConnector.getClient();RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);// Wait for 100 seconds seconds and automatically unlock it after lockTime secondsboolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);if (success) {try {return worker.invokeAfterLockAquire();} finally {lock.unlock();}}throw new UnableToAquireLockException();}
}

测试类:

@AutowiredRedisLocker distributedLocker;@RequestMapping(value = "/redlock")public String testRedlock() throws Exception{CountDownLatch startSignal = new CountDownLatch(1);CountDownLatch doneSignal = new CountDownLatch(5);for (int i = 0; i < 5; ++i) { // create and start threadsnew Thread(new Worker(startSignal, doneSignal)).start();}startSignal.countDown(); // let all threads proceeddoneSignal.await();System.out.println("All processors done. Shutdown connection");return "redlock";}class Worker implements Runnable {private final CountDownLatch startSignal;private final CountDownLatch doneSignal;Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {this.startSignal = startSignal;this.doneSignal = doneSignal;}public void run() {try {startSignal.await();distributedLocker.lock("test",new AquiredLockWorker<Object>() {@Overridepublic Object invokeAfterLockAquire() {doTask();return null;}});}catch (Exception e){}}void doTask() {System.out.println(Thread.currentThread().getName() + " start");Random random = new Random();int _int = random.nextInt(200);System.out.println(Thread.currentThread().getName() + " sleep " + _int + "millis");try {Thread.sleep(_int);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " end");doneSignal.countDown();}}

运行测试类:

Thread-48 start
Thread-48 sleep 99millis
Thread-48 end
Thread-49 start
Thread-49 sleep 118millis
Thread-49 end
Thread-52 start
Thread-52 sleep 141millis
Thread-52 end
Thread-50 start
Thread-50 sleep 28millis
Thread-50 end
Thread-51 start
Thread-51 sleep 145millis
Thread-51 end

从运行结果上看,在异步任务的情况下,确实是获取锁之后才能运行线程。不管怎么样,这是redis官方推荐的一种方案,可靠性比较高。有什么问题欢迎留言。

三、参考资料

https://github.com/redisson/redisson

《Redis官方文档》用Redis构建分布式锁 : http://ifeve.com/redis-lock/

A Look at the Java Distributed In-Memory Data Model (Powered by Redis) : https://dzone.com/articles/java-distributed-in-memory-data-model-powered-by-r

如何用Redlock实现分布式锁相关推荐

  1. 漫画:如何用Zookeeper实现分布式锁?

    转载自   漫画:如何用Zookeeper实现分布式锁? 什么是临时顺序节点? 让我们来回顾一下Zookeeper节点的概念: Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫 ...

  2. 分布式锁之三:Redlock实现分布式锁

    之前写过一篇文章<如何在springcloud分布式系统中实现分布式锁?>,由于自己仅仅是阅读了相关的书籍,和查阅了相关的资料,就认为那样的是可行的.那篇文章实现的大概思路是用setNx命 ...

  3. RedLock 实现分布式锁

    并发是程序开发中不可避免的问题,根据系统面向用户.功能场景的不同,并发的重视程度会有不同.从程序的角度来说,并发意味着相同的时间点执行了相同的代码,而有些情况是不被允许的,比如:转账.抢购占库存等,如 ...

  4. redlock java_Redlock分布式锁

    这篇文章主要是对 Redis 官方网站刊登的 Distributed locks with Redis 部分内容的总结和翻译. 什么是 RedLock Redis 官方站这篇文章提出了一种权威的基于 ...

  5. 如何用Redis实现分布式锁

    为什么需要分布式锁 在聊分布式锁之前,有必要先解释一下,为什么需要分布式锁. 与分布式锁相对就的是单机锁,我们在写多线程程序时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来互斥以保证共享变 ...

  6. 如何用redis实现分布式锁?这篇文章教你用redisson实现分布式锁,封装之后的方法更好用!

    使用redission实现分布式锁 添加配置类 import org.redisson.Redisson; import org.springframework.beans.factory.annot ...

  7. 临键锁如何实现幻读_如何用Redis实现分布式锁?

    作者:敖丙 来源:https://juejin.im/post/5e9473f5e51d454702460323 前言 上一章节我提到了基于zk分布式锁的实现,这章节就来说一下基于Redis的分布式锁 ...

  8. 面试题详解:如何用Redis实现分布式锁?

    说一道常见面试题: 使用Redis分布式锁的详细方案是什么? 一个很简单的答案就是去使用 Redission 客户端.Redission 中的锁方案就是 Redis 分布式锁的比较完美的详细方案. 那 ...

  9. 如何用MySQL实现分布式锁

    以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑.这样的话一份库存数据就有可能同时有多个应用来修改库存数据. 概述 以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑.这样的 ...

最新文章

  1. 【NLP招聘动态】太难啦!面试官盘点NLP近五年招聘动态
  2. python3 协程asyncio 调用步骤、阻塞和await、task任务、future对象 partial
  3. MySQL数据同步,出现Slave_SQL_Running:no和slave_io_running:no问题的解决方法
  4. C语言将正整数转换为字符串(附完整源码)
  5. C++ vector容器中用erase函数和迭代器删除重复元素问题分析
  6. C#中is vs as
  7. linux简单邮件系统,怎样简单搭建一个Linux操作系统邮件服务器
  8. 为什么现在年轻人都在寻找副业、兼职?难道只有物价生活成本上涨?
  9. 安装zabbix4.0
  10. 前后端分离登录验证功能实现案例
  11. windows下FreeImage编译
  12. Labview软件、NI数据采集卡、汽车发动机数据采集学习总结(一)
  13. 追梦App系列博客——需求分析报告
  14. 北京轨道交通新机场线“无人驾驶” 最高时速160公里
  15. VBA批量导入图片到多Word文档并加标题(会飞的鱼)
  16. Debug: defusedxml, CV_LOAD_IMAGE_UNCHANGED,CV_IMWRITE_JPEG_QUALITY,undistortPoints
  17. 每日一练(三) pointSprite(点精灵)
  18. 【案例28】银行对账单管理-在线下载优化记录
  19. 深度至尊之三信技术GHOST XP SP3装机精英白金版V11.3(NTFS)
  20. 如何运用包过滤技术实现个人防火墙

热门文章

  1. python权限不够无法写入_解决python使用pip安装模块的权限问题
  2. Mac下安装配置Python2和Python3并相互切换使用
  3. Python可视化中Matplotlib绘图(2.设置范围、标签、标题、图例(详细参数))
  4. opengl加载显示3D模型ms3d类型文件
  5. wxWidgets:wxPropertyGrid类用法
  6. wxWidgets:wxGraphicsRenderer类用法
  7. wxWidgets:wxDataViewEvent类用法
  8. boost::test模块带有自定义初始化测试的静态库使用变体
  9. boost::signals2::shared_connection_block相关的测试程序
  10. boost::signals2模块连接扩展槽的示例程序,使用信号的 connect_extended 和 extended_slot_type