利用Redisson实现订单关闭
实体类
为了方便测试,直接在测试类中的写内部类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderInfo {
/**
* 订单id
*/
private Integer id;
/**
* 描述:用来记录关闭时间,可以在测试时用来验证。关闭时间是否跟 expireTime相等
*/
private String description;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 过期时间:关闭时间
*/
private LocalDateTime expireTime;
}
生成订单
模拟生成订单并设置过期时间。
执行时会在redis创建2个key:
- redisson_delay_queue:{
<closeKey>} :订单数据 - redisson_delay_queue_timeout:{
<closeKey>} :zset类型,按时间戳排序
/**
* 创建订单,并设置过期时间
*
* @throws IOException
*/
@Test
void createOrder() {
RBlockingDeque<OrderInfo> blockingDeque = redissonClient.getBlockingDeque(closeKey);
RDelayedQueue<OrderInfo> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
// 100条订单
int n = 100;
Random random = new Random();
for (int i = 0; i < n; i++) {
// 1~100之间的正整数
int i1 = random.nextInt(100) + 1;
LocalDateTime now = LocalDateTime.now();
delayedQueue.offer(new OrderInfo(i + 1, "close: " + i1, now, now.plusSeconds(i1)), i1, TimeUnit.SECONDS);
}
}
关闭订单
关闭订单,这里会产生订阅。redis会出现redisson_delay_queue_channel。
/**
* 关闭订单
*
* @throws IOException
*/
@Test
void closeOrder() {
ReentrantLock lock = new ReentrantLock();
// 5个线程
int poolSize = 5;
List<CompletableFuture<Void>> futureList = new ArrayList<>();
for (int i = 0; i < poolSize; i++) {
futureList.add(CompletableFuture.runAsync(() -> {
RBlockingDeque<OrderInfo> blockingDeque = redissonClient.getBlockingDeque(closeKey);
// 加入监听
redissonClient.getDelayedQueue(blockingDeque);
while (true) {
OrderInfo take;
try {
take = blockingDeque.take();
} catch (Exception e) {
continue;
}
if (take == null) {
continue;
}
// 验证多次是否会重复关闭。正常里不会近,只是验证下。正式环境,可以删除
try {
lock.lock();
if(closed.contains(take.getId())){
log.info("测试是否会抢占:已存在其他线程处理关闭订单[{}]", take.getId());
}
closed.add(take.getId());
}finally {
lock.unlock();
}
// 处理订单关闭逻辑
log.info("订单[{}]关闭中。。。", take.getId());
log.info("订单[{}]已关闭!order={}", take.getId(), toJsonString(take));
}
}));
}
// 模拟正式环境中进程一直在运行,因为test时,没有join则会只执行一次出现消费完数据后进程就关闭了
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
}
完整测试类:
package cn.skyjilygao.demo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import static cn.skyjilygao.util.EntityUtil.toJsonString;
@Slf4j
@SpringBootTest
public class CloseOrderTests {
@Autowired
private RedissonClient redissonClient;
public static String closeKey = "order_close_test";
public volatile static Set<Integer> closed = new ConcurrentSkipListSet<>();
/**
* 创建订单,并设置过期时间
*
* @throws IOException
*/
@Test
void createOrder() {
RBlockingDeque<OrderInfo> blockingDeque = redissonClient.getBlockingDeque(closeKey);
RDelayedQueue<OrderInfo> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
int a = 100;
Random random = new Random(100);
for (int i = 0; i < a; i++) {
int i1 = random.nextInt(1 + i) + 1;
delayedQueue.offer(new OrderInfo(i + 1, "close: " + i1, LocalDateTime.now(), LocalDateTime.now().plusSeconds(i1)), i1, TimeUnit.SECONDS);
}
}
/**
* 关闭订单
*
* @throws IOException
*/
@Test
void closeOrder() {
ReentrantLock lock = new ReentrantLock();
// 5个线程
int poolSize = 5;
List<CompletableFuture<Void>> futureList = new ArrayList<>();
for (int i = 0; i < poolSize; i++) {
futureList.add(CompletableFuture.runAsync(() -> {
RBlockingDeque<OrderInfo> blockingDeque = redissonClient.getBlockingDeque(closeKey);
// 加入监听
redissonClient.getDelayedQueue(blockingDeque);
while (true) {
OrderInfo take;
try {
take = blockingDeque.take();
} catch (Exception e) {
continue;
}
if (take == null) {
continue;
}
try {
lock.lock();
if(closed.contains(take.getId())){
log.info("测试是否会抢占:已存在其他线程处理关闭订单[{}]", take.getId());
}
closed.add(take.getId());
}finally {
lock.unlock();
}
log.info("订单[{}]关闭中。。。", take.getId());
log.info("订单[{}]已关闭!order={}", take.getId(), toJsonString(take));
}
}));
}
// 模拟正式环境中进程一直在运行,因为test时,没有join则会只执行一次出现消费完数据后进程就关闭了
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderInfo {
private Integer id;
private String description;
private LocalDateTime createTime;
private LocalDateTime expireTime;
}
}
利用Redisson实现订单关闭的更多相关文章
- 嵌入式学习笔记(综合提高篇 第一章) -- 利用串口点亮/关闭LED灯
1 前言 从踏入嵌入式行业到现在已经过去了4年多,参与开发过的产品不少,有交换机.光端机以及光纤收发器,停车场出入缴费系统,二维码扫码枪,智能指纹锁以及数字IC芯片开发等; 涉及产品中中既有 ...
- oracle ebs 采购订单关闭之PL/SQL实现方法
应客户需求,需要写个脚本,批量关闭Bonus Item类型的采购订单,在metalink上搜索到一些方法,但是都测试不通.原来需要将代码生成一个并发程序.下面是测试成功的代码. 1.首先创建一个存储过 ...
- spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...
- C#队列Queue,利用队列处理订单
一.什么是队列 队列(Queue)代表了一个先进先出的对象集合.当您需要对各项进行先进先出的访问时,则使用队列.当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队. 这是摘抄网上的.做了 ...
- CMD命令利用tasklist与taskkill关闭程序
昨天远程服务器后,服务器无故卡住了,鼠标各种延迟与无反应,想在进程管理器里关闭程序也卡住,想点击重启系统也卡死无反应.纠结后win+R打开了cmd用shutdown重启才算搞定.重启期间思考了下,如何 ...
- 【Android】12.2 利用Intent启动和关闭Activity
分类:C#.Android.VS2015: 创建日期:2016-02-23 一.简介 Android应用程序中一般都有多个Activity,在Activity中,通过调用StartActivity方法 ...
- [典型漏洞分享]Insert型SQL注入的发现和利用,篡改订单金额
本例中的SQL注入和其它发现的SQL注入的主要区别:1.生成订单接口是一次性的,反复提交无效,因此,此类型的SQL注入比较难通过扫描器发现,需要人工提取和手动测试.2.Insert类型的SQL注入,不 ...
- 利用Redisson实现分布式锁及其底层原理解析
Redis介绍 参考地址:https://blog.csdn.net/turbo_zone/article/details/83422215 redis是一个key-value存储系统.和Memcac ...
- ant利用先进,ant订单具体解释,ant包,ant包装删除编译jar文件
在日常的项目开发,经常需要我们可以打包测试.特别是,开发环境是windows.实际情况是linux. 这样的话.一个非常大的程序猿将包,其中将包,这些软件包可能非常大,这里是真正的代码会改变的一部分, ...
- magento设置订单状态
<?php require_once('app/Mage.php');umask(0);Mage::app('default'); $order = Mage::getModel('sales/ ...
随机推荐
- Future详解
Future模式 [1]Future模式是多线程开发中常见的设计模式,它的核心思想是异步调用.对于Future模式来说,它无法立即返回你需要的数据,但是它会返回一个契约,将来你可以凭借这个契约去获取你 ...
- 自己动手写ls命令——Java版
自己动手写ls命令--Java版 介绍 在前面的文章Linux命令系列之ls--原来最简单的ls这么复杂当中,我们仔细的介绍了关于ls命令的使用和输出结果,在本篇文章当中我们用Java代码自己实现ls ...
- Mac Mojave 10.14.5安装python tesserocr
<1>先安装两个依赖库: brew install tesseract brew install leptonica 网上有些教程说要安装imagemagick,这里我觉得应该是不需要的, ...
- 洛谷P6060 [加油武汉]传染病研究
一道不错的数学题 Solution 看到约数个数就想到枚举约数,但对于每个询问都枚举显然不现实,但是我们可以将大致的方向锁定在这方面,是否可以预处理出一定的东西,然后低复杂度询问呢? 我们想到预处理出 ...
- Python学习笔记----操作字符串
1.字符串相加.列表相加.列表和字符串不能混着使用 #序列相加 a="hello" b="python" c=a+b print("字符串相加的结果& ...
- Spring中过滤器(Filter)和拦截器(Interceptor)的区别和联系
在我们日常的开发中,我们经常会用到Filter和Interceptor.有时同一个功能.Filter可以做,Interceptor也可以做.有时就需要考虑使用哪一个比较好.这篇文章主要介绍一下,二者的 ...
- 开箱即用 yyg-cli(脚手架工具):快速创建 vue3 组件库和vue3 全家桶项目
1 yyg-cli 是什么 yyg-cli 是优雅哥开发的快速创建 vue3 项目的脚手架.在 npm 上发布了两个月,11月1日进行了大升级,发布 1.1.0 版本:支持创建 vue3 全家桶项目和 ...
- DNS 解析 prefeath
本文将详细介绍DNS预解析prefetch的主要内容 概述 DNS(Domain Name System, 域名系统),是域名和IP地址相互映射的一个分布式数据库.DNS 查询就是将域名转换成 IP ...
- Codeforces Round #833 (Div. 2) A-D.md
比赛链接 A 题解 知识点:数学. 注意到 \(n\) 为奇数时,不考虑连续性,一共有 \(\lceil \frac{n}{2} \rceil ^2\) 个格子,接下来证明一定能凑成方块. 从下往上从 ...
- RocketMQ 在同程旅行的落地实践
本文作者:刘树东 - 同程艺龙技术专家 01/使用概况 同程旅行选择RocketMQ主要基于以下几个方面的考虑: 技术栈:公司主要以 Java 开发为主,因此我们倾向于选择一款用 Java 实现的MQ ...