自己写了个简单的redis分布式锁【我】
自己写了个简单的redis分布式锁
【注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用】
package redis; import java.util.Collections;
import java.util.Random;
import java.util.UUID; import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; public class RedisLock2 { JedisPool jedisPool;
private String key;
private String value;
//默认锁超时时间5秒
private Long timeout = 5L;
//加锁成功的时间起点
private Long startTime; /**
* 使用默认超时时间
* @param JedisPool
* @param key
*/
public RedisLock2(JedisPool JedisPool,String key) {
super();
this.jedisPool = JedisPool;
this.key = key;
value = System.currentTimeMillis()+"";
} /**
* 单独设置超时时间
* @param JedisPool
* @param key 锁的名称
* @param timeout 锁超时时间
*/
public RedisLock2(JedisPool JedisPool,String key,Long timeout) {
super();
this.jedisPool = JedisPool;
this.key = key;
this.timeout = timeout;
value = UUID.randomUUID().toString();
// System.out.println("创建锁时的value:"+value);
} /**
* 单次加锁,需要判断返回值【适用于获取不到锁就返回的业务场景】
* @return true:加锁成功; false:加锁失败
*/
public boolean lock() {
Jedis jedis = jedisPool.getResource();
boolean ok = jedis.set(key,value, "nx", "ex", timeout)!=null;
jedis.close();
if (!ok) {
//加锁失败
return false;
}
//加锁成功
startTime = System.currentTimeMillis();
return true;
} /**
* 阻塞重试加锁,默认时间间隔10毫秒
*/
public void lockRetry() {
lockRetry(null);
} /**
* 阻塞重试加锁,直到加锁成功【适用于一定要执行的业务】
* @param interval 重试时间间隔毫秒值
*/
public void lockRetry(Long interval) {
if (interval==null) {
//默认10毫秒重试一次
interval = 10L;
}else if(interval==0) {
//如果传值为0,则取10以内随机值
interval = (long) (new Random().nextInt(10) + 1);
}
int num = 0;
while (true) {
boolean b = lock();
num++;
if (b) {
System.out.println("加锁 "+num+" 次后成功");
break;
}
try {
//休息10毫秒后重试
Thread.sleep(interval);
System.out.println("有并发,休息:"+interval+"毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} /**
* 解锁【首先尝试用lua方式,如果redis的版本不支持lua,用普通方式】
* @return
*/
public String unlock() {
//解锁返回消息(非正常解锁时会打印,还可以在业务中解锁时判断此返回值)
String msg = "";
//加锁到解锁消耗时间
long timeConsume = System.currentTimeMillis() - startTime;
//超时直接返回
if (timeConsume > timeout * 1000) {
System.out.println("出现超时解锁-----------key:" + key + ",耗时毫秒:" + timeConsume);
// return false;
msg = "出现超时解锁--key:" + key + ",耗时毫秒:" + timeConsume;
return msg;
}
//这里是为了避免超时后,释放掉其他线程的同名锁
String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
Jedis jedis = jedisPool.getResource();
//执行lua脚本返回值
Object evalRtn = 0;
try {
evalRtn = jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value));
// System.out.println("lua解锁返回值:"+evalRtn);
} catch (Exception e) {
e.printStackTrace();
//如果当前redis不支持lua脚本,用下面方法,但是下面的代码不是原子操作,可能会有并发问题,这里忽略
String s = jedis.get(key);
if (value.equals(s)) {
//释放锁
jedis.del(key);
// return true;
msg = "解锁成功";
return msg;
}
}finally {
jedis.close();
}
if ((Long) evalRtn == 1) {
// return true;
msg = "解锁成功";
return msg;
}
System.out.println("出现其他异常解锁失败---------key:" + key);
// return false;
msg = "出现其他异常解锁失败--key:" + key;
return msg;
} //简单加锁测试
public static void main1(String[] args) throws InterruptedException {
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
//设置超时时间100秒
RedisLock2 redisLock = new RedisLock2(jedisPool,"lock1",100L);
//加锁
boolean lock = redisLock.lock();
//获取到锁才执行,获取不到不执行
if(lock) {
//执行业务逻辑(要保证业务逻辑执行时间小于锁超时时间)
System.out.println("我获取到锁了");
// Thread.sleep(2000);
}
System.out.println(redisLock.unlock());
} //开启多线程往redis中设置值,保证不覆盖(用单次锁在业务逻辑中循环阻塞)
public static void main2(String[] args) {
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
//原来是使用网上的一种锁
// DistributedLock lock = new DistributedLock(jedisPool); for (int i = 0; i < 3; i++) {
// final int k = i;
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10; j++) {
int k = j;
// 连接本地的 Redis 服务
// Jedis jedis = new Jedis("localhost");
// String code = null;
RedisLock2 myLock = null;
try {
//加分布式锁
// code = lock.lock("mylock");
myLock = new RedisLock2(jedisPool,"lock1",10L);
while (true) {
//不断获取锁
boolean lock = myLock.lock();
if (lock) {
//如果获取到则执行
// 从连接池中获取一个jedis对象
Jedis jedis = jedisPool.getResource();
if (!jedis.exists("a" + k)) {
jedis.set("a" + k, Thread.currentThread().getName());
jedis.expire("a" + k, 60);
System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
+ "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
try {
// Thread.sleep((long) (Math.random()*1000));
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: "
+ jedis.get("a" + k));
}
jedis.close();
break;//跳出循环
} } } finally {
//释放分布式锁
// lock.unLock("mylock",code);
//执行完解锁
myLock.unlock();
}
}
}
}).start();
}
} //开启多线程往redis中设置值,保证不覆盖(用阻塞锁)
public static void main(String[] args) {
//原来是使用rdissen锁
//获取redisson
// Config config = new Config();
// config.useSingleServer().setAddress("redis://localhost:6379");
// RedissonClient redisson = Redisson.create(config);
// //获取锁
// RLock lock = redisson.getLock("mylock"); // 创建连接池对象
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379); for (int i = 0; i < 3; i++) {
// final int k = i;
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10; j++) {
int k = j;
// 连接本地的 Redis 服务
// Jedis jedis = new Jedis("localhost");
RedisLock2 myLock = null;
try {
//加redisson分布式锁
// lock.lock();
//用我们自己写的重试锁【自定义锁非可重入锁,需要在线程中每次使用时都创建一个锁对象,多线程中只要名称相同就认为是同一个锁】
myLock = new RedisLock2(jedisPool,"lock1",10L);
//开启阻塞锁
myLock.lockRetry(3L);
//执行业务逻辑【因为用阻塞锁,无需判断返回值】
// 从连接池中获取一个jedis对象
Jedis jedis = jedisPool.getResource();
if (!jedis.exists("a" + k)) {
jedis.set("a" + k, Thread.currentThread().getName());
jedis.expire("a" + k, 60);
// System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
// + "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
try {
// Thread.sleep((long) (Math.random()*1000));
} catch (Exception e) {
e.printStackTrace();
}
} else {
// System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: "
// + jedis.get("a" + k));
}
jedis.close();
} finally {
//释放redisson分布式锁
// lock.unlock();
//用我自己定义的锁
myLock.unlock();
}
}
}
}).start();
} } }
自己写了个简单的redis分布式锁【我】的更多相关文章
- java架构之路-(Redis专题)简单聊聊redis分布式锁
这次我们来简单说说分布式锁,我记得过去我也过一篇JMM的内存一致性算法,就是说拿到锁的可以继续操作,没拿到的自旋等待. 思路与场景 我们在Zookeeper中提到过分布式锁,这里我们先用redis实现 ...
- redis分布式锁练习【我】
package redis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class ...
- Redis分布式锁实现简单秒杀功能
这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...
- 单实例redis分布式锁的简单实现
redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...
- redis 分布式锁的简单使用
RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...
- 利用redis分布式锁的功能来实现定时器的分布式
文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...
- redis分布式锁和消息队列
最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP ...
- redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis分布式锁的正确实现方式
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
随机推荐
- C#在代码中编写输出debug信息-类Debug的使用
文章:C# 的两种debug 方法 文章:C#跟踪和调试程序-Debug类使用 很全面的文章,可以仔细学习使用下. 文章:C#调试类 没有仔细看. 关键字:Debug类和Trace类有什么区别? 微软 ...
- linux服务器日志剖析
常规tomcat,apache,nginx,错误日志,还有项目log4j日志 tomcat (以tomcat7.082为例) tomcat日志配置 运行日志和访问日志结合在一起,先说下日志哪边配置,在 ...
- string::clear
void clear() noexcept;功能:把string对象置为空 #include <iostream>#include <string> using namespa ...
- python redis分布式锁改进
0X01 python redis分布式锁通用方法 REDIS分布式锁实现的方式:SETNX + GETSET 使用Redis SETNX 命令实现分布式锁 python 版本实现上述思路(案例1) ...
- [hdoj6415 Rikka with Nash Equilibrium][dp]
http://acm.hdu.edu.cn/showproblem.php?pid=6415 Rikka with Nash Equilibrium Time Limit: 10000/5000 MS ...
- spring 使用 context:property-placeholder 加载 多个 properties
一般使用PropertyPlaceholderConfigurer来替换占位符,例如: <bean class="org.springframework.beans.factory.c ...
- java第八次作业-继承
一.题目 编写一个应用程序,创建一个矩形类,类中具有长.宽两个成员变量和求周长的方法.再创建一个矩形类的子类------正方形类,类中定义求面积的方法.重写求周长的方法.在主类中,输入一个正方形边长, ...
- C# 判断一个string型的时间格式是否正确
在项目开发过程中,由于各种坑爹的需求,我们可能需要用户自己手动输入时间,不过这种功能一般都出现在自己家的后台里面,咳咳,言归正传.既然如此,那么这个时候我们就需要对用户手动输入的时间格式进行验证,方法 ...
- PyPI教程
Wiki PyPI The Python Package Index, abbreviated as PyPI and also known as the Cheese Shop (a referen ...
- VUE 异步数据传递给 component props 的问题
案例一 父组件parent.vue // asyncData为异步获取的数据,想传递给子组件使用 <template> <div> 父组件 <child :child-d ...