单实例redis分布式锁的简单实现
redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放.
直接上java代码, 如下:
package com.test;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* 简单的单实例redis分布式锁
* 没有实现的高级功能:锁的重入、锁的续约等
*
* @Author:tt
* @Description:
* @CreateTime:2019/6/12
*/
public class SingleRedisLock {
private JedisPool jedisPool;
/**
* 获取锁
*
* @param lockKey 锁的key
* @param lockVal 锁的val,可以利用来实现"避免误删别人锁"、"锁的重入"等功能
* @param lockMaxLifeTime 锁的最大生命时长,到期自动销毁,单位:毫秒
* @param tryWaitingTime 等待获取锁的超时时间,单位:毫秒
* @param waitingSleepTime 等待获取锁的阻塞周期,单位:毫秒,设置过短会造成cpu竞争,设置过长会造成浪费,需依赖于'具体业务平均的执行时长'
* @return
*/
public Boolean tryLock(String lockKey, String lockVal, int lockMaxLifeTime, int tryWaitingTime, int waitingSleepTime) {
//lua脚本,让逻辑简单清晰,同时保证原子性
//setNX:成功-1,失败-0
String lua = " if redis.call('set',KEYS[1],ARGV[1],'PX',ARGV[2],'NX') then return 1 else return 0 end ";
//获取锁的开始时间
Long tryBeginTime = System.currentTimeMillis();
//轮询
while (true) {
Long result = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
result = (Long) jedis.eval(lua, Arrays.asList(lockKey), Arrays.asList(lockVal, String.valueOf(lockMaxLifeTime)));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
try {
jedis.close();
} catch (Exception e) {
}
}
}
//获取锁成功
if (Long.valueOf(1).equals(result)) {
return true;
}
//当前时间
Long now = System.currentTimeMillis();
//获取等待超时,就不用获取了
if (now - tryBeginTime >= tryWaitingTime) {
return false;
}
try {
//阻塞等一会儿再重新去获取
TimeUnit.MILLISECONDS.sleep(waitingSleepTime);
} catch (InterruptedException e) {
}
}
}
/**
* 释放锁
*
* @param lockKey
* @param lockVal
* @return
*/
public void releaseLock(String lockKey, String lockVal) {
//如果lockVal是自己的再删除,防止误删,场景来源:当前锁的持有者操作时间太长,锁已经自动释放并被别人占有了
String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]) end ";
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.eval(lua, Arrays.asList(lockKey), Arrays.asList(lockVal));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
try {
jedis.close();
} catch (Exception e) {
}
}
}
}
//测试
public static void main(String[] args) {
//连接池
JedisPool jedisPool = new JedisPool(new GenericObjectPoolConfig(), "127.0.0.1", 6379, 2000, "test123");
SingleRedisLock simpleRedisLock = new SingleRedisLock();
simpleRedisLock.jedisPool = jedisPool;
//模拟10个并发
for (int i = 0; i < 10; i++) {
new Thread(() -> {
String lockKey = "TEST_LOCK_KEY";
String threadName = Thread.currentThread().getName();
//获取锁
Boolean locked = simpleRedisLock.tryLock(lockKey, threadName,
30000, 5000, 200);
//获取锁失败
if (!locked) {
System.err.println(">>> " + threadName + " 获取锁失败");
return;
}
//获取锁成功,模拟执行业务操作
System.out.println(">>> " + threadName + " 获取锁成功");
doShortBusiness();
//doLongBusiness();
//释放锁
simpleRedisLock.releaseLock(lockKey, threadName);
}).start();
}
try {
TimeUnit.MILLISECONDS.sleep(60000);
} catch (InterruptedException e) {
}
}
//短任务:100毫秒
static void doShortBusiness() {
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
}
}
//长任务:3秒
static void doLongBusiness() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
}
}
}
锁的高级功能包含锁的重入、锁的续约等, 当然为了保证锁的高可用, redis还有主从、集群等部署方式, 对应的锁的实现也有区别, 略微复杂, 不过有现成的框架可供我们参考使用, 比较知名的如Redisson, 一个强大的redis客户端, 当然包括对“分布式锁”的完美实现, 其支持redis单实例、哨兵、集群等模式。

单实例redis分布式锁的简单实现的更多相关文章
- Redis分布式锁实现简单秒杀功能
这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...
- redis 分布式锁的简单使用
RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...
- springmvc单Redis实例实现分布式锁(解决锁超时问题)
一.前言 关于redis分布式锁, 查了很多资料, 发现很多只是实现了最基础的功能, 但是, 并没有解决当锁已超时而业务逻辑还未执行完的问题, 这样会导致: A线程超时时间设为10s(为了解决死锁问题 ...
- 自己写了个简单的redis分布式锁【我】
自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...
- .NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用
环境:之前一直是使用serverStack.Redis的客服端,今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),版本为StackExch ...
- Redis分布式锁实例
maven依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</ ...
- Redis分布式锁
Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...
- Redlock(redis分布式锁)原理分析
Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...
- Redlock:Redis分布式锁最牛逼的实现
普通实现 说道Redis分布式锁大部分人都会想到:setnx+lua,或者知道set key value px milliseconds nx.后一种方式的核心实现命令如下: - 获取锁(unique ...
随机推荐
- 【python】range的用法
range的用法: >>> range(1,5) #代表从1到5(不包含5)[1, 2, 3, 4]>>> range(1,5,2) #代表从1到5,间隔2(不包含 ...
- group & user
例子 groupadd test 创建test用户组 useradd user1 创建user1用户 passwd user1 设置user1的密码 useradd user2 ...
- ORA-00904:"T1"."AREA_ID" :标识符无效
1.错误描写叙述 ORA-00904:"T1"."AREA_ID" :标识符无效 00904 . 00000 - "%s:invalid identi ...
- poj3254Corn Fields
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13765 Accepted: 7232 Desc ...
- tiny4412学习(三)之移植linux-4.x驱动(1)支持网卡驱动【转】
本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74160686 一.思路 上一节我们通过DNW将内核.文件系统.设备树文件烧入到内 ...
- Luogu3403跳楼机
https://zybuluo.com/ysner/note/1099616 题面 给你三个数\(x\),\(y\),\(z\),问你能够凑出多少个[1,\(h\)]之间的数. 解析 处理出\(y\) ...
- 特征变化--->特征向量中部分特征到类别索引的转换(VectorIndexer)
VectorIndexer: 倘若所有特征都已经被组织在一个向量中,又想对其中某些单个分量进行处理时,Spark ML提供了VectorIndexer类来解决向量数据集中的类别性特征转换. 通过为其提 ...
- 牛客小白月赛15 C 表单 ( map 使用)
链接:https://ac.nowcoder.com/acm/contest/917/C来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...
- Vue 柱状图
echarts.js作为国内的IT三巨头之一的百度的推出一款相对较为成功的开源项目,总体上来说有这样的一些优点 1.echarts.js容易使用 echarts.js的官方文档比较详细,而且官网中提供 ...
- curl 采集的时候遇到60报错怎么办?
1.到https://curl.haxx.se/ca/cacert.pem复制下文本粘贴到文件夹cart.pem 然后把catr.pem放到PHP的bin目录下 2.在php.ini中修改下面这句话, ...