模拟秒杀系统:

第一步:编写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. SpringMVC源码解析 - HandlerAdapter - @SessionAttributes注解处理

    使用SpringMVC开发时,可以使用@SessionAttributes注解缓存信息.这样业务开发时,就不需要一次次手动操作session保存,读数据. @Controller @RequestMa ...

  2. Android-开关机的广播

    在上一篇博客Android-sdcard广播的接收处理,中介绍了,如何订阅接收者,去接收系统发送的Sdcard状态改变广播,而这篇博客是订阅接收者,去接收开机/关机的广播 Android操作系统在开机 ...

  3. python signal

    在了解了Linux的信号基础之 后,Python标准库中的signal包就很容易学习和理解.signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时 ...

  4. 查看jar包的jdk版本并降级

    用解压工具打开jar包(例子都是用7zip)   进入到META-INF目录,查看MANIFEST.MF文件,查看Bulid-Jdk,下图就为1.7.0_55版本的JDK,这就表示jetty-serv ...

  5. cesium编程入门(八)设置材质

    cesium编程入门(八)设置材质 Cesium中为几何形状设置材质有多种方法 第一种方法 Material 直接构建Cesium.Material对象,通过设置Material的属性来进行控制,官方 ...

  6. ADB模块源码分析(二)——adb server的启动

    1. ADB Server的启动 前面我们讲到adb模块的源码在system/core/adb下面,通过查看Android.mk文件我们了解到这个adb 模块回编译生成连个可执行文件adb.adbd, ...

  7. enumerate 和 dict.items()

    对 list 遍历 a_list = [1,2,3] for index,iterm in enumerate(a_list): print(index,iterm) 对 dict 遍历 dict = ...

  8. bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)

    传送门 题解 看了半天完全没发现这东西和CDQ有什么关系…… 先把原序列翻转,求起来方便 然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a ...

  9. LOJ#6047. 「雅礼集训 2017 Day10」决斗(set)

    题面 传送门 题解 这么简单一道题我考试的时候居然只打了\(40\)分暴力? 如果我们把每个点的\(a_i\)记为\(deg_i-1\),其中\(deg_i\)表示有\(deg_i\)个数的\(A_i ...

  10. by python3-XSStrike 测试XSS

    一.概述: XSStrike是一个Cross Site Scripting检测套件,配备四个手写解析器,一个智能有效载荷生成器,一个强大的模糊引擎和一个非常快速的爬虫. XSStrike不是像其他工具 ...