从redis中取值如果不存在设置值,使用Redisson分布式锁【我】
用到的jar包:
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency> <!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.1</version>
</dependency>
测试代码:
package redis; 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 RedisThread { public static void main1(String[] args) {
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");
// 创建连接池对象
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
// 从连接池中获取一个jedis对象
Jedis jedis = jedisPool.getResource();
// synchronized (RedisThread.class) {
String v = jedis.get("a" + k);
// if (v == null) {
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) + "存在,值为: " + v);
}
// }
jedis.close();
}
}
}).start();
}
}
/* 不加锁的运行结果: 可以看到一个键比如 a0被赋值了很多次,说明有线程安全问题(原因是getKey 和 setKey 的方法不同步),
* 如果在单服务环境可以用synchronized来解决,但是如果分布式多节点服务,synchronized 就无效了
*
* 1556503338616--Thread-2--key:a0不存在,设置值为: Thread-2
* 1556503338616--Thread-1--key:a0不存在,设置值为: Thread-1
* 1556503338616--Thread-0--key:a0不存在,设置值为: Thread-0
* 1556503338622--Thread-2--key:a1不存在,设置值为: Thread-2 Thread-0--key:a1存在,值为:
* Thread-2 1556503338622--Thread-1--key:a1不存在,设置值为: Thread-1
* 1556503338627--Thread-2--key:a2不存在,设置值为: Thread-2
* 1556503338627--Thread-0--key:a2不存在,设置值为: Thread-0
* 1556503338628--Thread-1--key:a2不存在,设置值为: Thread-1
* 1556503338634--Thread-2--key:a3不存在,设置值为: Thread-2
* 1556503338634--Thread-0--key:a3不存在,设置值为: Thread-0
* 1556503338634--Thread-1--key:a3不存在,设置值为: Thread-1
* 1556503338644--Thread-2--key:a4不存在,设置值为: Thread-2
*/ public static void main(String[] args) {
//获取redisson
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
RedissonClient redisson = Redisson.create(config);
//获取锁
RLock lock = redisson.getLock("mylock"); 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");
// 创建连接池对象
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
try {
//加分布式锁
lock.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();
} finally {
//释放分布式锁
lock.unlock();
}
}
}
}).start();
}
} /* 加上分布式锁后的运行结果: 可以看到每一个键比如 a0只被赋值了一次,说明没有线程安全问题了
* (在这个例子中,redisson 连接redis只是用来做分布式锁,真正的业务中的redis操作用的还是其他连接方式,比如 jedisPool 等)
*
* 1556505103008--Thread-4--key:a0不存在,设置值为: Thread-4 Thread-2--key:a0存在,值为:
* Thread-4 Thread-3--key:a0存在,值为: Thread-4
* 1556505103035--Thread-4--key:a1不存在,设置值为: Thread-4 Thread-2--key:a1存在,值为:
* Thread-4 Thread-3--key:a1存在,值为: Thread-4
* 1556505103058--Thread-4--key:a2不存在,设置值为: Thread-4 Thread-2--key:a2存在,值为:
* Thread-4 Thread-3--key:a2存在,值为: Thread-4
* 1556505103080--Thread-4--key:a3不存在,设置值为: Thread-4 Thread-2--key:a3存在,值为:
* Thread-4 Thread-3--key:a3存在,值为: Thread-4
* 1556505103100--Thread-4--key:a4不存在,设置值为: Thread-4 Thread-2--key:a4存在,值为:
* Thread-4 Thread-3--key:a4存在,值为: Thread-4
* 1556505103126--Thread-4--key:a5不存在,设置值为: Thread-4 Thread-2--key:a5存在,值为:
* Thread-4 Thread-3--key:a5存在,值为: Thread-4
* 1556505103146--Thread-2--key:a6不存在,设置值为: Thread-2 Thread-4--key:a6存在,值为:
* Thread-2 Thread-3--key:a6存在,值为: Thread-2
* 1556505103165--Thread-4--key:a7不存在,设置值为: Thread-4 Thread-2--key:a7存在,值为:
* Thread-4 Thread-3--key:a7存在,值为: Thread-4
* 1556505103186--Thread-4--key:a8不存在,设置值为: Thread-4 Thread-2--key:a8存在,值为:
* Thread-4 1556505103197--Thread-4--key:a9不存在,设置值为: Thread-4
* Thread-2--key:a9存在,值为: Thread-4 Thread-3--key:a8存在,值为: Thread-4
* Thread-3--key:a9存在,值为: Thread-4
*/ }
---------------------------------------------------
注意:
如果不是想用分布式锁解决其他业务逻辑问题,而只是为了解决本文标题说的向redis中存入取出值(如果存在就取出,如果不存在就存入)的问题,那么完全可以用下面的方法来实现
其原理就是下面这个方法:
// jedis.set("key", "value", "nx", "ex", 50L); //第一个参数:key,第二个参数:value,第三、四个参数固定写法,第五个参数:超时毫秒值
// 上面这个方法其实就是redis的 setnx 和 expire 组合在一起的原子指令 (据说其是Redis2.8版本增加的新特性,但是我在2.4版本居然也能用)
public static void main(String[] args) {
for (int i = 0; i < 3; 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");
// 创建连接池对象
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
// 从连接池中获取一个jedis对象
Jedis jedis = jedisPool.getResource();
String setResult = jedis.set("a" + k, Thread.currentThread().getName(), "nx", "ex", 50L);
if (setResult == null) {
// 说明已经存在,设置值失败
System.out.println(Thread.currentThread().getName() + "--key:" + ("a" + k) + "存在,值为: "
+ jedis.get("a" + k));
} else {
// 说明设置值成功
System.out.println(System.currentTimeMillis() + "--" + Thread.currentThread().getName()
+ "--key:" + ("a" + k) + "不存在,设置值为: " + Thread.currentThread().getName());
}
jedis.close();
}
}
}).start();
}
}
// 运行结果: 说明这是没有问题的
// 也就是说,如果不是想用分布式锁解决其他业务逻辑问题,而只是为了解决向redis中存入取出值(如果存在就取出,如果不存在就存入)的问题,那么完全可以用上面的方法来实现
// 其原理就是下面这个方法:
// jedis.set("key", "value", "nx", "ex", 50L); //第一个参数:key,第二个参数:value,第三、四个参数固定写法,第五个参数:超时毫秒值
// 上面这个方法其实就是redis的 setnx 和 expire 组合在一起的原子指令 (据说其是Redis2.8版本增加的新特性,但是我在2.4版本居然也能用)
// 1556588977532--Thread-0--key:a0不存在,设置值为: Thread-0
// Thread-1--key:a0存在,值为: Thread-0
// Thread-2--key:a0存在,值为: Thread-0
// 1556588977535--Thread-0--key:a1不存在,设置值为: Thread-0
// Thread-2--key:a1存在,值为: Thread-0
// Thread-1--key:a1存在,值为: Thread-0
// 1556588977538--Thread-0--key:a2不存在,设置值为: Thread-0
// Thread-2--key:a2存在,值为: Thread-0
// Thread-1--key:a2存在,值为: Thread-0
// 1556588977541--Thread-0--key:a3不存在,设置值为: Thread-0
// 1556588977545--Thread-0--key:a4不存在,设置值为: Thread-0
// Thread-1--key:a3存在,值为: Thread-0
// Thread-2--key:a3存在,值为: Thread-0
// Thread-2--key:a4存在,值为: Thread-0
// 1556588977553--Thread-0--key:a5不存在,设置值为: Thread-0
// Thread-1--key:a4存在,值为: Thread-0
// 1556588977558--Thread-0--key:a6不存在,设置值为: Thread-0
// 1556588977562--Thread-0--key:a7不存在,设置值为: Thread-0
// Thread-1--key:a5存在,值为: Thread-0
// Thread-2--key:a5存在,值为: Thread-0
// 1556588977566--Thread-0--key:a8不存在,设置值为: Thread-0
// Thread-2--key:a6存在,值为: Thread-0
// Thread-1--key:a6存在,值为: Thread-0
// 1556588977578--Thread-0--key:a9不存在,设置值为: Thread-0
// Thread-2--key:a7存在,值为: Thread-0
// Thread-1--key:a7存在,值为: Thread-0
// Thread-2--key:a8存在,值为: Thread-0
// Thread-1--key:a8存在,值为: Thread-0
// Thread-2--key:a9存在,值为: Thread-0
// Thread-1--key:a9存在,值为: Thread-0
从redis中取值如果不存在设置值,使用Redisson分布式锁【我】的更多相关文章
- 多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中【我】
多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中 package com.xxx.xx.reve.service; import java.util.ArrayL ...
- Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua
开心一刻 我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门 昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:"看咱前面,想不到这么丑都有人要." 女朋友 ...
- 时间轮机制在Redisson分布式锁中的实际应用以及时间轮源码分析
本篇文章主要基于Redisson中实现的分布式锁机制继续进行展开,分析Redisson中的时间轮机制. 在前面分析的Redisson的分布式锁实现中,有一个Watch Dog机制来对锁键进行续约,代码 ...
- Jquery系列:checkbox 获取值、选中、设置值、事件监听等操作
<div id="divId" class="divTable"> <div class="tableBody"> ...
- C# Winform中WebBrowser给网页中的input控件赋值/设置值
订阅WebBrowser的DocumentCompleted事件,在里面写入 private void browser_DocumentCompleted(object sender, WebBrow ...
- 《Redis深度历险:核心原理和应用实践》千帆竞发——分布式锁
- spring-boot 中实现标准 redis 分布式锁
一,前言 redis 现在已经成为系统缓存的必备组件,针对缓存读取更新操作,通常我们希望当缓存过期之后能够只有一个请求去更新缓存,其它请求依然使用旧的数据.这就需要用到锁,因为应用服务多数以集群方式部 ...
- Redis 中的事务分析,Redis 中的事务可以满足ACID属性吗?
Redis 中的事务 什么是事务 1.原子性(Atomicity) 2.一致性(Consistency) 3.隔离性(Isolation) 4.持久性(Durability) 分析下 Redis 中的 ...
- redis中如何对 key 进行分类
因为redis中的 hash是不支持设置过期时间的,如果我们要 设置过期时间,还要分类存储,可以用下面折中的方法 其实就是我们把 key 定义的有规律一些,通过在key的字符串内部 分类,上图只是因为 ...
随机推荐
- 设计模式 - 单例模式(Singleton Pattern)
单例模式 介绍 模式:创建型 意图:保证一个类只有一个实例,并提供一个访问它的全局访问点 解决:一个全局使用的类频繁地创建与销毁 场景: 唯一序列号 web中的计数器 I/O与数据库的连接 …… 实现 ...
- CAD 在ARCGIS中的坐标系问题
近期在使用服务(文本写入dxf方式)导出CAD的时候发现导出的CAD文件和原始数据在ArcMap中叠加后不能重合,出现了错位的现象. 查看CAD文件后发现CAD的坐标系及投影和数据不一致导致的.遇到这 ...
- OpenCL洗牌函数shuffle
在OpenCL中,经常会碰到会对向量的多个分量进行交叉运算的情况,比如 float4 d4; //input float scale; //input float2 mix_0 = mix((floa ...
- JavaScript 节流函数 Throttle 详解
在浏览器 DOM 事件里面,有一些事件会随着用户的操作不间断触发.比如:重新调整浏览器窗口大小(resize),浏览器页面滚动(scroll),鼠标移动(mousemove).也就是说用户在触发这些浏 ...
- Go 反射
基本了解 在Go语言中,大多数时候值/类型/函数非常直接,要的话,定义一个.你想要个Struct type Foo struct { A int B string } 你想要一个值,你定义出来 var ...
- centos7的主机名配置
centos7的主机名配置 方法一:通过配置文件/etc/hostname (重启后生效) 方法二:通过命令hostnamectl set-hostname 新主机名(会自动把主机名改为小写) ...
- 一:SqlServer中的 CEILING函数和 FLOOR函数以及ROUND()
例如 1.ROUND() 格式为ROUND(y1,y2,y3) y1:要被四舍五入的数字y2:保留的小数位数 y3:为0,可以不写,y1进行四舍五入,不为0则y1不进入四舍五入,如果y1有值就直接根据 ...
- C#几个经常用到的字符串的截取
string str="123abc456";int i=3;1 取字符串的前i个字符 str=str.Substring(0,i); // or str=str.Remov ...
- windows docker redis
拉取docker docker pull hub.c.163.com/library/redis:latest 启动docker docker run -p 6379:6379 -d hub.c.16 ...
- 【博客导航】Nico博客导航汇总
摘要 介绍本博客关注的内容大类.任务.工具方法及链接,提供Nico博文导航. 导航汇总 [博客导航]Nico博客导航汇总 [导航]信息检索导航 [导航]Python相关 [导航]读书导航 [导航]FP ...