JMeter模拟并发请求

news/2024/10/23 6:37:54/

        PostMan不是严格意义上的并发请求工具,实际是串行的,如果需要测试后台接口并发时程序的准确性,建议采用JMeter工具。

案例:JMeter设置20个并发卖票请求,查看后台是否存在超卖的情况

 方式一:一共10张票,票余额作为成员属性放在控制器中,没做任何的锁控制

package com.gingko.controller;
import com.gingko.common.GenericWebResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Random;@RestController
@RequestMapping("ticket")
@Slf4j
public class TicketController {private static int TICKET_AMOUNT = 10;//一共10张票@PostMapping("/sell")public GenericWebResult sell() {GenericWebResult result = null;if(TICKET_AMOUNT > 0) {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}TICKET_AMOUNT--;System.out.println("售票成功:余票" + TICKET_AMOUNT);result = GenericWebResult.ok("售票成功:余票",TICKET_AMOUNT);}else {result = GenericWebResult.error("售票失败:余票",TICKET_AMOUNT);System.out.println("售票失败:余票" + TICKET_AMOUNT);}return result;}
}

运行结果及分析: 

从运行结果可以看出,在高并发的时候,出现了超卖和数据不一致的问题

 方式二:一共10张票,票余额作为成员属性放在控制器中,卖票的请求方法上加锁synchronized

package com.gingko.controller;
import com.gingko.common.GenericWebResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Random;@RestController
@RequestMapping("ticket")
@Slf4j
public class TicketController {private static int TICKET_AMOUNT = 10;//一共10张票@PostMapping("/sell")public synchronized GenericWebResult sell() {GenericWebResult result = null;if(TICKET_AMOUNT > 0) {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}TICKET_AMOUNT--;System.out.println("售票成功:余票" + TICKET_AMOUNT);result = GenericWebResult.ok("售票成功:余票",TICKET_AMOUNT);}else {result = GenericWebResult.error("售票失败:余票",TICKET_AMOUNT);System.out.println("售票失败:余票" + TICKET_AMOUNT);}return result;}
}

运行结果及分析: 

 从运行结果可以看出,在高并发的时候,没有出现超卖或数据不一致问题,数据结果符合预期。

方式三:TicketController对象多例,并且TICKET_AMOUNT属性不是static,每个对象各自持有

package com.gingko.controller;
import com.gingko.common.GenericWebResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Random;@RestController
@RequestMapping("ticket")
@Slf4j
@Scope("prototype") //多例
public class TicketController {private int TICKET_AMOUNT = 10;@PostMapping("/sell")public GenericWebResult sell() {GenericWebResult result = null;if(TICKET_AMOUNT > 0) {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}TICKET_AMOUNT--;System.out.println("售票成功:余票" + TICKET_AMOUNT);result = GenericWebResult.ok("售票成功:余票",TICKET_AMOUNT);}else {result = GenericWebResult.error("售票失败:余票",TICKET_AMOUNT);System.out.println("售票失败:余票" + TICKET_AMOUNT);}return result;}
}

运行结果及分析:  

从程序可以看出,20个并发请求,后台生成了20个TicketController实例,每个实例内部都持有属性TICKET_AMOUNT = 10,sell方法执行后,TICKET_AMOUNT = 9

方式一、方式二与方式三示意图区别如下:

方式一、二,堆内存中只有一个TicketController实例,并且TICKET_AMOUNT不属于实例对象,属于共享的数据区,对这种共享数据并发操作时,需要锁机制控制,防止出现数据不一致。

方式三,并发请求多少,堆内存中生成多少个TicketController实例,并且每个TicketController实例各自持有TICKET_AMOUNT,访问各自的成员属性也就不会发生数据不一致问题。


http://www.ppmy.cn/news/1541254.html

相关文章

Java毕业设计 基于SpringBoot发卡平台

Java毕业设计 基于SpringBoot发卡平台 这篇博文将介绍一个基于SpringBoot发卡平台,适合用于Java毕业设计。 功能介绍 首页 图片轮播 商品介绍 商品详情 提交订单 文章教程 文章详情 查询订单  查看订单卡密 客服   后台管理 登录 个人信息 修改密码 管…

前端将cvs格式数据导出为Excel表

使用ExcelJS库:ExcelJS(也称为SheetJS)是一个强大的JavaScript库,它允许在浏览器和Node.js中处理Excel文件。你可以使用它来读取CSV文件的内容,并将其转换为Excel格式。以下是一个基本的示例代码: import X…

vue video播放m3u8监控视频

很关键的问题 vite创建的项目不需要import ‘videojs-contrib-hls’ 导入就报错 直接添加如下代码即可 html5: {vhs: {overrideNative: true},nativeVideoTracks: false,nativeAudioTracks: false,nativeTextTracks: false} 下面是完整组件示例 <template><div>…

【C++篇】深度解析类与对象(上)

目录 引言 一、类的定义 1.1类定义的基本格式 1.2 成员命名规范 1.3 class与struct的区别 1.4 访问限定符 1.5 类的作用域 二、实例化 2.1 类的实例化 2.2 对象的大小与内存对齐 三、this 指针 3.1 this指针的基本用法 3.2 为什么需要this指针&#xff1f; 3.3 t…

新手学STM32的话,先学标准库还是HAL库?

大家好&#xff0c;我是麦鸽&#xff0c;最近有网友提问 用STM32的话&#xff0c;是学标准库还是HAL库&#xff1f; 对于新手&#xff0c;我想说&#xff0c;不要和自己过不去&#xff0c;一开始不要搞得太难&#xff0c;要循序渐进。 新手经常会问的问题&#xff0c;先学51还是…

88.【C语言】文件操作(5)

目录 文件的随机读写 1.fseek函数 代码示例 运行结果 2.ftell函数 代码示例 运行结果 3.rewind函数 代码示例 运行结果 承接79.【C语言】文件操作(4)文章 文件的随机读写 1.fseek函数 声明:int fseek ( FILE * stream, long int offset, int origin ); 格式:fsee…

itext自定义pdf

pom坐标 <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency>字体文件可以…

go 包相关知识

在Go语言中&#xff0c;包的引用和搜索路径是由环境变量GOPATH和GO111MODULE共同决定的。 GOPATH环境变量&#xff1a;这个变量定义了默认的工作目录&#xff0c;Go命令行工具将会在这个目录下查找包文件。这个目录通常包含三个子目录&#xff1a;src、bin和pkg。 src目录包含…