package com.vian.user.service;

import org.junit.Test;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction; import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /** 秒杀测试 */
public class SecondKillTest {
@Test
public void getResult() {
Jedis jedis = JedisPoolUtil.getJedis();
String goodsResult = jedis.get("goodsResult:user102");
System.out.println(goodsResult);
} @Test
public void test() throws IOException, InterruptedException {
/** 初始化商品 */
initGoods(); /** 1000线程抢购100个商品 */
ExecutorService executorService = Executors.newFixedThreadPool(20);
CountDownLatch count = new CountDownLatch(10000);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
executorService.execute(new SecondKillHandlder("user" + i));
count.countDown();
}
executorService.shutdown();
count.await();
long time = System.currentTimeMillis() - startTime;
System.out.println("共耗时:" + time + "毫秒");
// JedisPoolUtil.close();
System.in.read();
} /** 初始化商品数量 */
private void initGoods() {
Jedis jedis = JedisPoolUtil.getJedis();
jedis.set("goods:iphone8", "100"); // 设置100个商品
JedisPoolUtil.returnRes(jedis);
} /** 秒杀处理线程 */
private static class SecondKillHandlder implements Runnable {
String goodsKey = "goods:iphone8"; // 监视的key 当前秒杀商品的数量
Jedis jedis;
String userName; public SecondKillHandlder(String userName) {
this.userName = userName;
} @Override
public void run() {
while (true) {
try {
jedis = JedisPoolUtil.getJedis();
// watch 监视一个key,当事务执行之前这个key发生了改变,事务会被打断
jedis.watch(goodsKey);
int currentGoodsCount = Integer.parseInt(jedis.get(goodsKey)); // 当前剩余商品数量
if (currentGoodsCount <= 0) {
System.out.println("商品已抢完," + userName + "---> 抢购失败 XXX");
break;
}
Transaction tran = jedis.multi(); // 开启事务
tran.incrBy(goodsKey, -1); // 商品数量-1
List<Object> exec = tran.exec(); // 执行事务
if (CollectionUtils.isEmpty(exec)) {
System.out.println(userName + "---> 抢购失败,继续抢购");
Thread.sleep(1);
} else {
exec.forEach(
succ -> {
String succStr =
userName
+ "===========================> 抢购到第【"
+ ((100 - currentGoodsCount) + 1)
+ "】份商品,该商品剩余:"
+ succ.toString();
System.out.println(succStr);
jedis.set("goodsResult:" + userName, succStr); // 业务代码,处理抢购成功
});
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.unwatch();
JedisPoolUtil.returnRes(jedis);
}
}
}
}
} private static class JedisPoolUtil {
private static JedisPool pool; private static void createJedisPool() {
// 建立连接池配置参数
JedisPoolConfig config = new JedisPoolConfig();
// 设置最大连接数
config.setMaxTotal(100);
// 设置最大阻塞时间,记住是毫秒数milliseconds
config.setMaxWaitMillis(1000);
// 设置空间连接
config.setMaxIdle(10);
// 创建连接池
pool = new JedisPool(config, "192.168.31.201", 6379, 2000, null, 3);
} /** 在多线程环境同步初始化 */
private static synchronized void poolInit() {
if (pool == null) createJedisPool();
} /**
* 获取一个jedis 对象
*
* @return
*/
public static Jedis getJedis() { if (pool == null) poolInit();
return pool.getResource();
} /**
* 归还一个连接
*
* @param jedis
*/
public static void returnRes(Jedis jedis) {
pool.returnResource(jedis);
} public static void close() {
pool.close();
}
}
}

java基于redis事务的秒杀实现的更多相关文章

  1. Java基于redis实现分布式锁(SpringBoot)

    前言 分布式锁,其实原理是就是多台机器,去争抢一个资源,谁争抢成功,那么谁就持有了这把锁,然后去执行后续的业务逻辑,执行完毕后,把锁释放掉. 可以通过多种途径实现分布式锁,例如利用数据库(mysql等 ...

  2. Java基于Redis的分布式锁

    分布式锁,其实最终还是要保证锁(数据)的一致性,说到数据一致性,基于ZK,ETCD数据一致性中间件做分数是锁,才是王道.但是Redis也能满足最基本的需求. 参考: https://www.cnblo ...

  3. 基于redis的cas实现

    cas是我们常用的一种解决并发问题的手段,小到CPU指令集,大到分布式存储,都能看到cas的影子.本文假定你已经充分理解一般的cas方案,如果你还不知道cas是什么,请自行百度 我们在进行关系型数据库 ...

  4. 一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.简述Redis事务实现 2.redis集群方案 3.redis主从复制的核心原理 4.CAP理论,BASE理论 5.负 ...

  5. Redis事务和实现秒杀功能的实现

    今天带着学生学习了Redis的事务功能,Redis的事务与传统的关系型数据库(如MySQL)有所不同,Redis的事务不能回滚. Redis中使用multi.exec.discard.watch.un ...

  6. Java实现排行榜基于Redis

    访问我的博客 前言 排行榜作为互联网应用中几乎必不可少的一个元素,其能够勾起人类自身对比的欲望,从而来增加商品的销量.排行榜的实现方式基本大同小异,大部分都基于 Redis 的有序集合 sorted ...

  7. redis watch 加 事务实现秒杀

    <?php   //redis watch 加 事务实现秒杀  $redis = new redis();  $result = $redis->connect('10.10.10.119 ...

  8. 基于redis的高并发秒杀的JAVA-DEMO实现!

    在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能.假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EX ...

  9. java事务/springboot事务/redis事务

    java事务(数据库事务):jdbc事务--ACID springboot事务:@Transactional--ACID redis事务:命令集合 将redis事务与mysql事务对比:   Mysq ...

随机推荐

  1. emacs 文本替换

    文本替换方法: M-% (query-replace) 输入 响应 SPC 或者 y 替换当前匹配并前进到下一个匹配处 DEL 或者 n 忽略此次匹配并前进到下一个匹配处 . 替换当前匹配并退出 , ...

  2. java的环境变量配置失败(java.exe、javaw.exe、javaws.exe优先级问题冲突)

    前言:首先安装了intelliJ Idea 其次安装了JDK 1.8 配置完三个系统变量后,java和javac执行不通过 配置过程 1.我的电脑(右键)--->属性---->高级---& ...

  3. 【题解】P2922 [USACO08DEC]秘密消息Secret Message

    \(\text{Tags}\) 字典树,统计 题意: 给出两组\(\text{0/1}\)串\(\text{A,B}\),求解\(\text{A}\)中某串是\(\text{B}\)中某串的前缀,和\ ...

  4. [十二省联考2019]D1T1异或粽子

    嘟嘟嘟 做这题之前,强烈推荐先把这道题切了P1631序列合并. 这两道题思路基本一模一样. 首先把异或处理成前缀异或,然后维护一个大根堆,每一次取出堆顶加到答案里面,然后把堆顶所在元素的次大的异或值放 ...

  5. Java 7 和 Java 8 中的 HashMap原理解析

    HashMap 可能是面试的时候必问的题目了,面试官为什么都偏爱拿这个问应聘者?因为 HashMap 它的设计结构和原理比较有意思,它既可以考初学者对 Java 集合的了解又可以深度的发现应聘者的数据 ...

  6. 使用VScode配合chrome实现网页自动刷新

    1.使用插件:livereload 2.VScode商店中搜索上述插件安装 3.Chrome商店中搜素上述插件安装 并设置允许访问文件网址: 4.在两方插件都打开的情况下,VScode中按下ctrl+ ...

  7. Spring Boot与缓存

    ---恢复内容开始--- JSR-107.Spring缓存抽象.整合Redis 一.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider, CacheMana ...

  8. 台达PLC实现远程下载程序

    台达PLC实现远程下载程序 日期:2019-04-27                    时间    08:33:57 让物联变得更简单 18-09-2411:25 明明在公司调试没问题的设备一到 ...

  9. bs4模块

    1.导入模块 from bs4 import BeautifulSoup 2.创建对象 Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它 ...

  10. bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 题面: 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: ...