自己写了个简单的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实现分布式锁.虽然网上已经有各种介 ...
随机推荐
- 对于vector中高效删除中间元素的技巧
众所周知,vector是连续存储空间,只提供高效的尾部删除方法pop_back() ,在中间删除的效率很低,那么如果大家想快速删除中间元素该如何实现? 话不多说,看代码: //移除vector元素,最 ...
- 解析.conf配置文件
解析.conf配置文件 解析.conf配置文件 解析.conf配置文件
- usb相关
https://github.com/daynix/UsbDk/tree/master/UsbDk 更应该关注下libusb
- 如何创建javabeans实例
如何创建javabeans实例 1.像使用普通java类一样,创建javabean实例 创建一个用户类的javabeans package com.po; /** * * 用户类 * @author ...
- SpringBoot 项目启动 Failed to convert value of type 'java.lang.String' to required type 'cn.com.goldenwater.dcproj.dao.TacPageOfficePblmListDao';
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tac ...
- python-windows安装相关问题
1.python的环境配置,有些时候是没有配置的,需要在[系统环境]-[path]里添加. 2.安装pip:从官网下载pip包,然后到包目录==>python setup.py install ...
- selenium web driver
WebDriver 支持的浏览器 IE6-10 FireFox大部分版本 Chrome Safari Opera Andrioid 系统上的自带浏览器 IOS系统上自带浏览器 HtmlUnit的无界面 ...
- paramiko远程上传下载文件
import paramiko import sys user = "root" pwd = " # 上传文件 def sftp_upload_file(server_p ...
- java web项目为什么我们要放弃jsp?(转)
前戏: 以前的项目大多数都是java程序猿又当爹又当妈,又搞前端(ajax/jquery/js/html/css等等),又搞后端(java/mysql/Oracle等等). 随着时代的发展,渐渐的许多 ...
- word黏贴图片显示不出来
word图片转存,是指UEditor为了解决用户从word中复制了一篇图文混排的文章粘贴到编辑器之后,word文章中的图片数据无法显示在编辑器中,也无法提交到服务器上的问题而开发的一个操作简便的图片转 ...