JMeter多线程测试时assetId被后续线程值覆盖该如何正确存取?
问题根因
__setProperty设置的是JMeter全局属性,所有线程共享读写权限,多线程并发修改同一属性名自然会出现覆盖问题。你当前的用法相当于所有线程共用一个全局变量存ID,最终只会保留最后写入的线程对应的值。
解决方案
按你实际的测试场景选择对应方案即可:
场景1:创建资产、删除资产在同一个线程组的同一次迭代内
这是绝大多数性能测试的常规场景,根本不需要使用全局属性。JSON提取器提取的assetId本身就是线程局部变量,每个线程的变量空间完全独立,不会互相干扰。直接在Delete请求里引用${assetId}即可,不需要做任何属性设置操作。
场景2:创建、删除逻辑分属不同线程组
需要给每个线程/迭代的ID生成独立的全局属性名,避免重名覆盖:
- 设置属性的时候,用线程号拼接属性名,把原BeanShell断言的内容替换为:
${__setProperty(assetId_${__threadNum}, ${assetId},)}
如果同一个线程要跑多轮迭代,还要加上迭代号区分:${__setProperty(assetId_${__threadNum}_${__jm__<替换为你的线程组名称>__idx}, ${assetId},)} - 删除请求调取属性的时候,用同样的规则拼接属性名即可:
${__property(assetId_${__threadNum})}
场景3:需要汇总所有生成的assetId后续统一批量删除
建议改用JSR223后置处理器(优先选Groovy语言,性能远高于BeanShell)存储ID到线程安全的全局集合:
- 创建资产后添加JSR223后置处理器,写入代码:
// 全局集合仅初始化一次 if (props.get("assetIdList") == null) { props.put("assetIdList", Collections.synchronizedList(new ArrayList<>())) } // 写入当前ID,加锁避免并发写入异常 synchronized(props.get("assetIdList")) { props.get("assetIdList").add(vars.get("assetId")) } - 需要批量删除的时候,遍历
props.get("assetIdList")即可获取所有生成的ID。
额外建议
JMeter 3.1之后已经不推荐使用BeanShell相关组件,高并发测试场景下BeanShell性能瓶颈非常明显,所有BeanShell断言/后置处理器都建议替换为JSR223组件,选择Groovy语言执行。
内容的提问来源于stack exchange,提问作者Sujith
相关产品推荐
相关产品推荐

