redis分布式锁实现控制并发
来源:互联网 发布:eggnog数据库 编辑:程序博客网 时间:2024/06/06 18:00
最近项目有一个关于征信协议生成pdf,要求客户签订的第一份协议生成pdf,由于是服务器集群,所以要用到分布式锁的概念。
写完后,写了个例子总结了下,直接上例子
import java.util.HashSet;
import java.util.Set;import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.data.redis.core.TimeoutUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
public class Test {
static Set<HostAndPort> haps_dest_dev = new HashSet<HostAndPort>();
static JedisCluster jedisCluster;
static {
haps_dest_dev.add(new HostAndPort("172.29.0.97", 6379));
haps_dest_dev.add(new HostAndPort("172.29.0.97", 6389));
haps_dest_dev.add(new HostAndPort("172.29.0.97", 6399));
haps_dest_dev.add(new HostAndPort("172.29.0.98", 6379));
haps_dest_dev.add(new HostAndPort("172.29.0.98", 6389));
haps_dest_dev.add(new HostAndPort("172.29.0.98", 6399));
jedisCluster = new JedisCluster(haps_dest_dev);
}
/** 毫秒与毫微秒的换算单位 1毫秒 = 1000000毫微秒 */
public static final long MILLI_NANO_CONVERSION = 1000 * 1000L;
/** 默认超时时间(毫秒) */
public static final long DEFAULT_TIME_OUT = 1000;
// private volatile boolean locked = false;
/**
* 获取锁
* @param timeout 获取锁的等待时间 毫秒
* @param expireSecs 锁的有效时间,必须大于0 毫秒
* @return
*/
private boolean lock(String lockKey, long timeout, int expireSecs) throws InterruptedException {
if (expireSecs <= 0) {
throw new IllegalArgumentException("Param expireSecs must lager than zero.");
}
long nano = System.nanoTime();
timeout *= MILLI_NANO_CONVERSION;
try {
while ((System.nanoTime() - nano) < timeout) {
long expires = System.currentTimeMillis() + expireSecs + 1;
// 5秒之后锁到期
String expiresStr = String.valueOf(expires); //锁到期时间
// 获取到锁
if (jedisCluster.setnx(lockKey, String.valueOf(expiresStr)) == 1) {
// lock acquired
// locked = true;
jedisCluster.expire(lockKey, (int) TimeoutUtils.toSeconds(expireSecs, TimeUnit.MILLISECONDS));
return true;
}
// 没有获取到锁
String currentValueStr = jedisCluster.get(lockKey);
// expireMsecs(5秒)锁的有效期内无法进入if判断,如果锁超时了
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
//判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的
// lock is expired
// 如果锁超时重新设置
String oldValueStr = jedisCluster.getSet(lockKey, expiresStr);
//获取上一个锁到期时间,并设置现在的锁到期时间,
//只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
// 值相同说明是同一个线程的操作,获取锁成功
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
//防止误删(覆盖,因为key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,但是因为什么相差了很少的时间,所以可以接受
//如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁
// lock acquired
// locked = true;
jedisCluster.expire(lockKey, (int) TimeoutUtils.toSeconds(expireSecs, TimeUnit.MILLISECONDS));
return true;
} else {
// 被其他线程抢先获取锁
// locked = false;
}
}
// 锁没有超时,继续等待
}
Thread.sleep(3, RandomUtils.nextInt(500));
} catch (Exception e) {
throw new RuntimeException("Locking error", e);
}
return false;
}
/**
* 释放锁
*/
public void releaseLock(String lockKey){
try {
long current = System.currentTimeMillis();
// 避免删除非自己获取得到的锁
if (current < Long.valueOf(jedisCluster.get(lockKey)))
jedisCluster.del(lockKey);
// locked = false;
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Test t = new Test();
try {
if (t.lock("lock:aa", DEFAULT_TIME_OUT, 5000)) {
System.out.println("获取锁");
} else {
System.out.println("未获取锁");
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
阅读全文
0 0
- redis分布式锁实现控制并发
- 如何利用Redis分布式锁实现控制并发
- 使用redis 实现分布式锁,处理并发问题
- redis并发问题 && 分布式锁
- Redis实现分布式锁
- Redis 分布式锁实现
- Redis 分布式锁实现
- Redis实现分布式锁
- redis实现分布式锁
- Redis实现分布式锁
- 分布式锁redis实现
- Redis 分布式锁实现
- redis分布式锁实现
- redis实现分布式锁
- Redis分布式锁实现
- redis分布式锁实现
- redis实现分布式锁
- Redis分布式锁实现
- 织梦cms模板下载:响应式机械螺丝设备网站模板
- Linux下子进程的异步等待
- jQuery选择器
- STM32 Bootload 程序
- 快速在本地搭建https项目
- redis分布式锁实现控制并发
- Golang 如何定义一个接口类型的切片,它可以用来存储混合类型的数据,又如何自定义错误信息输出,以及如何定义变参函数,还有字符串多种拼接方式
- 局部打印内容
- 【微信公众号开发】自我学习第五章:Curl的基础 / accessToken获取 / 微信服务器IP获取
- crontab命令的使用
- vc++运行mspdb60.dll丢失?vc++运行数据时弹出“mspdb60.dll丢失”怎么办。
- 自动化测试 uiautomator 入门
- 浅谈对于企业级系统架构的理解
- 【资源共享】完整版RK3399芯片手册《RK3399 Technical Reference Manual 1.4》