JMeter自定义采样器同步

时间:2014-05-13 13:34:40

标签: java multithreading synchronization jmeter

我正在开发一个JMeter测试计划,用于对Web服务进行性能测试。整个测试计划的主要部分包括两个步骤。

  1. 从服务器检索ID列表(通过Get-request)
  2. 获取其中一个ID并使用它执行某些操作(通过Post-request)
  3. 如果我使用单线程计划,一切都按预期进行,但只要我使用多个线程,就会陷入竞争状态。问题是,第二步更改了可用ID列表,因此:如果线程B在线程A完成步骤2之前检索ID列表,则线程B可能获得与线程A相同的ID,这导致线程B出错试图完成第2步。不知何故,这是多线程环境中竞争条件的经典例子。 由于JMeter没有提供定义关键代码块的可能性,我决定编写自己的自定义Java采样器,扩展JMeter-AbstractJavaSamplerClient,覆盖runTest()a.s.o.在runTest() - 实现中,我获取了一个ReentrantLock并使用它来锁定关键代码块。关键是,JMeter似乎并不关心那个锁,我根本就不明白为什么......如果我通过远程调试使用Eclipse调试我的代码我看到几个线程同时进入锁定的代码,情况不应该如此。我也尝试了使用synchronize进行完整的runTest() - 实现的老式方法,但这也不起作用。

    有没有人有什么需要改变的建议?或者至少解释为什么这不起作用?

    提前致谢!

3 个答案:

答案 0 :(得分:2)

另一种解决方法是编译一个简单的java类,编译它并将其放入{JMETER_HOME}\apache-jmeter-3.1\lib\ext\文件夹。

import java.util.*;

public class Global {
    public static Map map = new Hashtable();
}

使用CMD将其导出到jar文件中

jar cvfe {EXPORT_JAR_NAME}.jar ClassName {CLASS_FILE_NAME}.class

将文件放入{JMETER_HOME}\apache-jmeter-3.1\lib\ext\文件夹。

创建测试操作并将JSR223 PreProcessor添加到测试计划中 Show Image

import java.util.concurrent.Semaphore;

Global.map.clear();

Global.map.put("sem", new Semaphore(1));;

创建另一个测试操作并将JSR223 PreProcessor添加到测试计划中Show Image

log.info(ctx.getThreadNum() + " ACQUIRE");
Global.map.get("sem").acquire();
for (def i = 0; i < 100; i++) {
  // Do something
  log.info(ctx.getThreadNum() + " DO SOMETHING " + i);
}
Global.map.get("sem").release();
log.info(ctx.getThreadNum() + " RELEASE");

它应该克服竞争条件,因为信号量在线程组之间同步。

答案 1 :(得分:0)

如何在不必编写自己的采样器的情况下处理它有两个选项。

  1. 最简单,最直接的解决方法是使用__threadNum函数作为ID的参数,以便每个线程都可以运行自己的ID
  2. 使用Beanshell脚本删除当前正在使用的变量,以确保没有其他线程会选择相同的变量。
  3. 任何Beanshell测试元素(采样器,后处理器,预处理器,断言等)都可以访问名为vars的内容,这是JMeterVariables类实例的简写。所以你应该可以使用:

    vars.put("key", "value"); // to add a variable
    vars.remove("key"); // to remove variable
    

    测试中的任何地方的方法。

    有关Beanshell食谱的详细信息和种类,请参阅How to use BeanShell: JMeter's favorite built-in component指南。

答案 2 :(得分:0)

我终于让它运行了...我没有声明我的Lock是静态的...因此有几个线程可能进入关键代码块。