模拟秒杀系统:

第一步:编写Service

package com.payease.service;

/**
* liuxiaoming
* 2017-12-14
*/
public interface SecKillService {
/**
* 查询秒杀活动特价商品的信息
*
* @param productId
* @return
*/
String querySecKillProductInfo(String productId); /**
* 模拟不同用户秒杀同一商品的请求
*
* @param productId
* @return
*/
void orderProductMockDiffUser(String productId);
}

第二步:编写Redis加锁解锁工具类

package com.payease.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; /**
* liuxiaoming
* 2017-12-14
*/
@Component
@Slf4j
public class RedisLock { @Autowired
private StringRedisTemplate stringRedisTemplate; /**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
//currentValue=A 这两个线程的value都是B 其中一个线程拿到锁
String currentValue = stringRedisTemplate.opsForValue().get(key);
//如果锁过期
if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
//获取上一个锁的时间
String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
} /**
* 解锁
* @param key
* @param value
* @return
*/
public void unlock(String key, String value) {
String currentVaule = stringRedisTemplate.opsForValue().get(key);
try {
if (!StringUtils.isEmpty(currentVaule) && currentVaule.equals(value)) {
stringRedisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error("【redis分布式锁】解锁异常,{}" , e);
} }
}

第三步:编写Service实现类

package com.payease.service.impl;

import com.payease.exception.SellException;
import com.payease.service.RedisLock;
import com.payease.service.SecKillService;
import com.payease.utils.KeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.HashMap;
import java.util.Map; /**
* liuxiaoming
* 1027-12-14
*/
@Service
public class SecKillServiceImpl implements SecKillService { @Autowired
private RedisLock redisLock; private static final int TIMOUT = 10 * 1000; //超时时间 10秒 /**
* 中秋活动 秒杀月饼 限量100000
*/
static Map<String, Integer> products;
static Map<String, Integer> stock;
static Map<String, String> orders; static {
products = new HashMap<>();
stock = new HashMap<>();
orders = new HashMap<>();
products.put("abc123456", 10000);
stock.put("abc123456", 10000);
} private String queryMap(String productId) {
return "中秋活动,月饼特价,限量份"
+ products.get(productId)
+ " 还剩:" + stock.get(productId) + " 份"
+ " 该商品成功下单用户数目:"
+ orders.size() + " 人";
} @Override
public String querySecKillProductInfo(String productId) {
return queryMap(productId);
} /**
* 描述逻辑
*
* @param productId
*/
@Override
public void orderProductMockDiffUser(String productId) { //加锁
long time = System.currentTimeMillis() + TIMOUT;
if (!redisLock.lock(productId, String.valueOf(time))) {
throw new SellException(110, "没抢到,换个姿势再试一遍呀");
}
//1. 查询该商品库存,为0则活动结束。
int stockNum = stock.get(productId);
if (stockNum == 0) {
//库存不足
throw new SellException(100, "活动已经结束,请留意下次活动");
} else { orders.put(KeyUtil.getUniqueKey(), productId);
stockNum = stockNum - 1;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stock.put(productId, stockNum);
} //解锁
redisLock.unlock(productId, String.valueOf(time));
} /*@Override
public synchronized void orderProductMockDiffUser(String productId) {
int stockNum = stock.get(productId);
if (stockNum == 0) {
//库存不足
throw new SellException(100, "活动已经结束,请留意下次活动");
} else { orders.put(KeyUtil.genUniqueKey(), productId);
stockNum = stockNum - 1;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stock.put(productId, stockNum);
} }*/
}

第四步:编写controller

package com.payease.controller;

import com.payease.service.SecKillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/skill")
@Slf4j
public class SecKillController { @Autowired
private SecKillService secKillService; /**
* 查询秒杀活动特价商品的信息
* @param productId
* @return
*/
@GetMapping("/query/{productId}")
public String query(@PathVariable String productId)throws Exception
{
return secKillService.querySecKillProductInfo(productId);
} /**
* 秒杀,没有抢到获得"哎呦喂,xxxxx",抢到了会返回剩余的库存量
* @param productId
* @return
* @throws Exception
*/
@GetMapping("/order/{productId}")
public String skill(@PathVariable String productId)throws Exception
{
log.info("@skill request, productId:" + productId);
secKillService.orderProductMockDiffUser(productId);
return secKillService.querySecKillProductInfo(productId);
}
}

第五步:启动项目 查看浏览器 进行压测

1.查看秒杀情况 http://127.0.0.1:8080/sell/skill/query/abc123456

2. 在Mac终端输入命令: ab -n 500 -c 100 http://127.0.0.1:8080/sell/skill/order/abc123456
进行压测

3.查看浏览器 http://127.0.0.1:8080/sell/skill/query/abc123456

注:

压测模拟并发:

springboot项目:Redis分布式锁的使用(模拟秒杀系统)的更多相关文章

  1. SpringBoot集成Redis分布式锁以及Redis缓存

    https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...

  2. springBoot实现redis分布式锁

    参考:https://blog.csdn.net/weixin_44634197/article/details/108308395 .. 使用redis的set命令带NX(not exist)参数实 ...

  3. springboot+redis分布式锁-模拟抢单

    本篇内容主要讲解的是redis分布式锁,这个在各大厂面试几乎都是必备的,下面结合模拟抢单的场景来使用她:本篇不涉及到的redis环境搭建,快速搭建个人测试环境,这里建议使用docker:本篇内容节点如 ...

  4. 用压测模拟并发、并发处理(synchronized,redis分布式锁)

    使用工具:Apache an 测压命令: ab -n 100 -c 100 http://www.baidu.com -n代表模拟100个请求,-c代表模拟100个并发,相当于100个人同时访问 ab ...

  5. spring-boot 中实现标准 redis 分布式锁

    一,前言 redis 现在已经成为系统缓存的必备组件,针对缓存读取更新操作,通常我们希望当缓存过期之后能够只有一个请求去更新缓存,其它请求依然使用旧的数据.这就需要用到锁,因为应用服务多数以集群方式部 ...

  6. redis分布式锁在springboot中的实现

    理论知识   redis分布式锁的实现方案请参考文章 如何优雅地用redis实现分布式锁 本案例简介   以秒杀活动为例子,在多线程高并发的情况下需要保证秒杀业务的线程安全性,确保秒杀记录与所扣库存数 ...

  7. 项目中用到了Redis分布式锁,了解一下背后的原理

    前言 以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存.现在博主在某金融平台实习,发现Redis在生产中并不只是当作缓存这么简单.在我接触到的项目中,Redis起到了一个分布式锁的作用 ...

  8. 基于SpringBoot AOP面向切面编程实现Redis分布式锁

    基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...

  9. Redis分布式锁升级版RedLock及SpringBoot实现

    分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问,Java中我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的方式.但是现在 ...

随机推荐

  1. 如何从官网开始 mongo java

    http://docs.mongodb.org/ecosystem/drivers/ MongoDB Driver Documentation Getting Started Installation ...

  2. Altera FPGA 开启引脚片上上拉电阻功能

    本博文以矩阵键盘实验为例,介绍了如何开启FPGA管脚的片上上拉电阻. Cyclone IV E FPGA的通用输入输出管脚都支持内部弱上拉电阻,但是时钟输入脚不支持.所以,当需要上拉电阻的信号(如本例 ...

  3. 试题 C: 数列求值 蓝桥杯

    试题 C: 数列求值本题总分: 10 分[问题描述]给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和.求第 20190324 项的最后 4 位数字.[ ...

  4. [Postgres]Postgres复制表

    在需要把含有分表的总表备份的时候想到的笨办法,如果有什么更先进的办法万望告知. 比如TableOld是由TableOld1,TableOld2,TableOld3组合而成,现在需要对TableOld进 ...

  5. lucene学习笔记(四)lucene分词详解

    分词器的核心类 Analyzer SimpleAnalyzer StopAnalyzer WhitespaceAnalyzer StandardAnalyzer TokenStream 分词器做好处理 ...

  6. tomcat-java_opts设置说明

    The JAVA_OPTS environment variable can be used to specify additional arguments to the JVM JBoss will ...

  7. Discuz showmessage函数解析[转]

    函数相关文件 \source\function\function_core.php\source\function\function_message.php ## 函数解释 /** * 显示提示信息 ...

  8. CSharp读取json配置文件内容

    步骤 读取配置文件转换成字符串,代码如下 string contents = System.IO.File.ReadAllText("config.json"); 注意:该语句会抛 ...

  9. JPA之@GeneratedValue注解

    JPA的@GeneratedValue注解,在JPA中,@GeneratedValue注解存在的意义主要就是为一个实体生成一个唯一标识的主键(JPA要求每一个实体Entity,必须有且只有一个主键), ...

  10. Asp.net Core IIS上安装部署及502.5错误解决

    总结: 安装Microsoft Visual C++ 2015 Redistributable(https://www.microsoft.com/en-us/download/details.asp ...