简介
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的锁给删除掉。
但是单实例有个缺点,如果Redis服务器宕机,那么就会导致无法获取锁,后果就是无法执行后续方法。假如采用主从复制,因为Redis主从是异步的,就是master不会等待slave接收了数据再响应客户端。考虑这种情景,线程A请求锁,master写入成功后发送给slave前master宕机,触发故障转移,slave升级为master,正好这时线程B又来获取锁并且成功,那么线程A和B都可以执行任务,所以用这种方式的话,宁愿不要有slave。不过这种属于小概率错误,在一个保证永不宕机的环境下这个方式没有任何问题。
 
示例
以下Demo类中的调用线程可以假设是分布在多个JVM进程中的线程,为了方便测试,共享数据也是设置到Redis中,客户端是Jedis。
import redis.clients.jedis.Jedis;
 
/**
* 单实例Redis分布式锁工具类
*/
public class RedisLockUtils {
/**
* 加锁
*
* @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.RedisLockUtils;
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 = RedisLockUtils.lock(jedis, key, uuid, 30);
} while (result == false);
int value = Integer.parseInt(jedis.get("value"));
jedis.set("value", ++value + "");
} finally {
// RedisLockUtils.unlock(jedis, key, uuid);
RedisLockUtils.unlockByLua(jedis, key, uuid);
jedis.close();
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算法
参考官网。

Redis 4.0.2分布式锁的Java实现的更多相关文章

  1. 使用Redis SETNX 命令实现分布式锁

    基于setnx和getset http://blog.csdn.net/lihao21/article/details/49104695 使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其 ...

  2. 分布式锁2 Java非常用技术方案探讨之ZooKeeper

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

  3. redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  4. Redis整合Spring实现分布式锁

    spring把专门的数据操作独立封装在spring-data系列中,spring-data-redis是对Redis的封装 <dependencies> <!-- 添加spring- ...

  5. 分布式锁2 Java非常用技术方案探讨之ZooKeeper 【转载】

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

  6. Redis、Zookeeper实现分布式锁——原理与实践

    Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...

  7. Redis 上实现的分布式锁

    转载Redis 上实现的分布式锁 由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多 ...

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

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

  9. 使用Redis SETNX 命令实现分布式锁(转载)

    使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法. SETNX命令简介 命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在. 若 ...

随机推荐

  1. 设计模式 | Spring中用到的设计模式,你知道几个?

    设计模式无处不在,因为它就来自于我们的日常生活,提炼于生活经验. 正握在你手中的手机,不能用220V的电压直接充电,需要一个专门的电源适配器(充电器)才行.摆在你桌上的电脑也是一样的,都需要" ...

  2. zstd和zip操作6g的文本

    ssd是在固态硬盘上的时间 1.txt   7038308223 bytes 都是默认级别 ======================================== zstd-v1.4.4-w ...

  3. lidar激光雷达领域的分类

    lidar领域可以按分为以下五方面: 激光雷达系统与装备 激光雷达系统与开发 激光雷达光源 激光雷达探测 多光谱激光雷达系统 单光子激光雷达系统 低成本RGB-D距离传感器 激光雷达元器件及装备等 激 ...

  4. 万级K8s集群背后etcd稳定性及性能优化实践

    背景与挑战 随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云容器服务TKE服务数量和核数大幅增长, 另一方面我们提供的容器服务类型(TKE托管及独立集群.EKS弹性集群.edge边缘计算集群.m ...

  5. Tesseract OCR 安装尝试

    1.简介 Tesseract是一个图像识别项目,将图中的文字识别出来.将一个.jpg .png 等等 的图片作为输入,.txt作为识别内容输出 Tesseract项目GitHub地址 2.安装 你可以 ...

  6. 手写mybatis框架

    前言 很久没有更新mybatis的源码解析了,因为最近在将自己所理解的mybatis思想转为实践. 在学习mybatis的源码过程中,根据mybatis的思想自己构建了一个ORM框架 .整个代码都是自 ...

  7. HDU-1754-I Hate It(单点更新+区间查询)

    很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有 ...

  8. 平衡二叉搜索树/AVL二叉树 C实现

    //AVTree.h #ifndef MY_AVLTREE_H #define MY_AVLTREE_H typedef int ElementType; struct TreeNode { Elem ...

  9. PyTorch ResNet 使用与源码解析

    本章代码:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson8/resnet_inference.py 这篇文章首先会简 ...

  10. 20190928-02使用Redis客户端Jedis连接Redis,以及用Java代码操作Redis 000 030

    启动redis package com.yujie.jedis; import java.util.HashMap; import java.util.Map; import java.util.Se ...