简介
Redis分布式锁算法有两种,一种是单个Redis实例下的,一种是多个Redis实例的Redlock算法。
官方推荐Redlock算法,但是这个算法需要比较多的Redis实例而且是完全互相独立,不存在主从复制或者其他集群协调机制的,所以不太适合小项目。
单Redis实例
原理
某个线程调用Redis命令 SET key value NX PX 30000。
这个命令的意思是,仅在不存在key的时候才能被执行成功(NX选项),并且这个key有一个30秒的自动失效时间(NX选项)。key的失效时间是一个调用线程独占锁的时间。这个key的value最好是一个随机数,value在所有的调用线程中必须是唯一的。value是随机数主要是为了更安全的释放锁,释放锁的时候使用脚本告诉Redis,只有key存在并且存储的值和我指定的值一样才能告诉我删除成功。可以通过以下Lua脚本实现:
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end。
使用这种方式释放锁可以避免删除别的调用线程获取成功的锁。举个例子:线程A取得资源锁,当线程A运行完毕其他操作后要释放锁时,原来的锁早已超时并且被Redis自动释放,并且在这期间资源锁又被线程B再次获取到。如果仅使用DEL命令将key删除,那么这种情况就会把线程B的锁给删除掉。使用Lua脚本就不会存在这种情况,因为脚本仅会删除value等于线程的value的key。
但是这个方法有个缺点,如果Redis服务器宕机,那么就会导致无法获取锁,后果就是无法执行后续方法。假如采用主从复制,因为Redis主从是异步的,就是master不会等待slave接收了数据再响应客户端。考虑这种情景,线程A请求锁,master写入成功后发送给slave前master宕机,触发故障转移,slave升级为master,正好这时线程B又来获取锁并且成功,那么线程A和B都可以执行任务,所以用这种方式的话,宁愿不要有slave。不过这种属于小概率错误,在一个保证永不宕机的环境下这个方式没有任何问题。
示例
以下Demo类中的调用线程可以假设是分布在多个JVM进程中的线程,为了方便测试,共享数据也是设置到Redis中。
import redis.clients.jedis.Jedis;
/**
* 单实例Redis分布式锁工具类
*/
public class RedisDLUtils {
/**
* 加锁
*
* @param jedis
* @param key
* @param value
* @param seconds
* @return
*/
public static Boolean lock(Jedis jedis, String key, String value, int seconds) {
String result = jedis.set(key, value, "NX", "EX", seconds);
return (result != null) && ("OK".equals(result));
}
/**
* 释放锁
*
* @param jedis
* @param key
* @param value
* @return
*/
public static Boolean unlock(Jedis jedis, String key, String value) {
if (value.equals(jedis.get(key))) {
return jedis.del(key) == 1;
}
return false;
}
/**
* 通过执行Lua脚本释放锁
*
* @param jedis
* @param key
* @param value
* @return
*/
public static Boolean unlockByLua(Jedis jedis, String key, String value) {
String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
long result = (long) jedis.eval(script, 1, key, value);
return result == 1;
}
}
import com.ice.util.RedisDLUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
public class Demo {
public static void main(String[] args) throws Exception {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMinIdle(10);
jedisPoolConfig.setMaxIdle(50);
jedisPoolConfig.setMaxTotal(150);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.164.128", 6379);
CountDownLatch countDownLatch = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
new Thread(() -> {
String uuid = UUID.randomUUID().toString();
String key = "lock";
Jedis jedis = jedisPool.getResource();
try {
boolean result = false;
do {
result = RedisDLUtils.lock(jedis, key, uuid, 30);
} while (result == false);
int value = Integer.parseInt(jedis.get("value"));
jedis.set("value", ++value + "");
} finally {
jedis.close();
// RedisDLUtils.unlock(jedis, key, uuid);
RedisDLUtils.unlockByLua(jedis, key, uuid);
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
try (Jedis jedis = new Jedis("192.168.164.128", 6379)) {
int value = Integer.parseInt(jedis.get("value"));
System.out.println("value=" + value);
}
}
}
Redlock算法

转载于:https://www.cnblogs.com/gjb724332682/p/8609677.html

Redis 4.0.2分布式锁的Java实现相关推荐

  1. 用 Redis 实现分布式锁(Java 版)

    用 Redis 实现分布式锁(Java 版) 核心代码 完整代码   分布式锁是一种解决分布式临界资源并发读写的一种技术.本文详细介绍了在 Java 中使用 Redis 实现分布式锁的方法.为了方便, ...

  2. redisson redlock(基于redisson框架和redis集群使用分布式锁)

    一.关于分布式锁的两篇文章 文章1 文章2 二.redis分布式锁存在的问题 redis实现分布式锁有很多种方案,比较完善的方案应该是用setNx + lua进行实现.简单实现如下: java代码-加 ...

  3. redis set 超时_redis分布式锁3种实现方式对比分析总结

    我在这篇文章提到了分布式锁,但没有展开来讲,抛砖引玉,今天就来说说高并发服务编程中的redis分布式锁. 这里罗列出3种redis实现的分布式锁,并分别对比说明各自特点. Redis单实例分布式锁 实 ...

  4. Redis应用学习——Redis事务与实现分布式锁

    2019独角兽企业重金招聘Python工程师标准>>> 1. Redis事务机制 1. 与MySQL等关系数据库相同,Redis中也有事务机制,Redis的事务实质上是命令的集合,但 ...

  5. 分布式锁1 Java常用技术方案

    前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资 ...

  6. Day137-139.尚品汇:制作SKU、商品详情、项目优化:Redis缓存、redssion分布式锁

    目录 Day5  制作SKU 1. 制作SKU 2. 多表查询如何写? 3. 制作SKU 4. Thymeleaf Day06 商品详情 1. 获取分类信息 2. 获取最新价格信息 3. 获取销售信息 ...

  7. Redis与Zookeeper实现分布式锁的区别

    Redis与Zookeeper实现分布式锁的区别 1.分布式锁解决方案 1.采用数据库 不建议 性能不好 jdbc 2.基于Redis实现分布式锁(setnx)setnx也可以存入key,如果存入ke ...

  8. 在 Redis 上实现的分布式锁

    由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多技术上的难点,在这我将对每一个有用 ...

  9. Redis使用setnx实现分布式锁及其问题、优化

    最近在工作中用到了分布式锁,然后查了很多分布式锁的实现方式.比较熟悉redis或者说,redis的用法比较简单,所以查了一下redis使用setnx实现分布式锁的方式.其中有一篇文章搜索到的次数最多, ...

最新文章

  1. python解释器哪一年_Python即Python解释器的发展史
  2. 汇编解析(3)-nasm基础、物理地址
  3. boost::system模块实现初始化顺序的测试程序
  4. 【Linux】一步一步学Linux——cut命令(44)
  5. nmap常用的扫描命令
  6. iOS开发之网络编程--获取文件的MIMEType
  7. Python抓取打印机硒鼓和组件剩余量的爬虫
  8. 整理的C++面试,这些是最为常见的
  9. java -D參数简化增加多个jar【简化设置classpath】
  10. IDA6.1下载符号表时卡死
  11. 一个真实的用户画像实例。
  12. 【笨木头Cocos2dx 038】战争迷雾效果 第01章_要探索,不要地图全开!
  13. 简记_硬件工程师解读RS-422/RS-485接口
  14. HTTP相关:DNS防止劫持
  15. 消息推送----微信小程序,公众号
  16. ps Adobe 存储为 Web 所用格式
  17. SpringCloud 基础教程(八)-Hystrix熔断器(上)
  18. 人人网上市七年芳华不再 市值缩水逾97%仅余空壳?
  19. 如何让nginx不返回304
  20. C语言中——三种方法判断是偶数还是奇数

热门文章

  1. android应用中插入admob广告
  2. Go程序性能分析pprof
  3. caffe web demo 搭建
  4. 图像处理之快速均值模糊(Box Blur)
  5. Laravel 引入自定义类库或第三方类库
  6. [python](windows)分布式进程问题:pickle模块不能序列化lambda函数
  7. 记一次意外的自定义控件
  8. Objective-C:MRC(引用计数器)获得对象所有权的方式(init、retain、copy等)
  9. 你不知道的关于计算机大师 Dijkstra 的事情
  10. qt5使用mysql