自己写了个简单的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分布式锁【我】的更多相关文章

  1. java架构之路-(Redis专题)简单聊聊redis分布式锁

    这次我们来简单说说分布式锁,我记得过去我也过一篇JMM的内存一致性算法,就是说拿到锁的可以继续操作,没拿到的自旋等待. 思路与场景 我们在Zookeeper中提到过分布式锁,这里我们先用redis实现 ...

  2. redis分布式锁练习【我】

    package redis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class ...

  3. Redis分布式锁实现简单秒杀功能

    这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...

  4. 单实例redis分布式锁的简单实现

    redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...

  5. redis 分布式锁的简单使用

    RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...

  6. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

  7. redis分布式锁和消息队列

    最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP ...

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

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

  9. Redis分布式锁的正确实现方式

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

随机推荐

  1. TLS1.3&TLS1.2形式化分析(二)

    1.下面是TLS1.2和TLS1.3握手协议过程 ,明显的可以看出存在不同 . 我们先说TLS1.2的握手过程明显是比TLS1.3的握手过多了一次.在TLS1.3中舍弃了之前RSA的协商过程,然后基于 ...

  2. Linux网络管理——nslookup

    使用参考: https://www.computerhope.com/unix/unslooku.htm https://www.thegeekstuff.com/2012/02/dig-comman ...

  3. SmtpClient 发送邮件

    利用SmtpClient 代码发送邮件. 简单测试代码: static void Main(string[] args) { MailMessage msg = new MailMessage(); ...

  4. PHP获取不到url传递参数中#&等特殊字符解决方法

    有些符号在URL中是不能直接传递的,无法传入PHP处理,比如#&等符号,通过$_GET是获取不到的,比如一个域名https://localhost/url.php?url=yangyufei+ ...

  5. mybatis-oracle 新增序列

    1.参考 https://blog.csdn.net/qq_29001173/article/details/82106853 2.思考: 2.1获取序列下一个值:seq_car.nextval 2. ...

  6. C语言calloc()函数:分配内存空间并初始化——stm32中的应用

    经常在代码中看到使用malloc来分配,然后memset清零,其实calloc更加方便,一句顶两句~ 头文件:#include <stdlib.h> calloc() 函数用来动态地分配内 ...

  7. python面向对象基础(四)内置方法 __xx__之new与init

    __init__和__new__方法 __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将 ...

  8. java开发时,eclipse设置编码

    修改eclipse默认工作空间编码方式,General——Workspace——Text file encoding 修改工程编码方式,右击工程——Properties——Resource——Text ...

  9. 23、自动装配-Aware注入Spring底层组件&原理

    23.自动装配-Aware注入Spring底层组件&原理 Aware 接口,提供了类似回调函数的功能 自定义组件想要使用Spring 容器底层的一些组件(Application Context ...

  10. python自动华 (十七)

    Python自动化 [第十七篇]:jQuery介绍 jQuery jQuery是一个兼容多浏览器的javascript库,核心理念是write less,do more(写得更少,做得更多),对jav ...