Patze
Patze

Reputation: 307

JMeter custom sampler synchronization

I´m working on a JMeter testplan which is meant to preformance-test a webservice. The main part of the whole testplan consists of two steps.

  1. Retrieve a list of IDs from the server (via Get-request)
  2. Take one of these IDs and do something with it (via Post-request)

If I use a singlethreaded plan, everything works out as expected, but as soon as I use more than one thread, I get into a race condition. The problem is, that the 2nd step changes the list of avaiable IDs, thus: if thread B retrieves the ID-list before thread A finished step 2, thread B might get the same ID as thread A which leads to an error when thread B tries to fulfill step 2. Somehow a classical example of race conditions in a multithreaded environment. As JMeter doesn´t provide the possibility for defining critical code blocks, I decided to write my own custom Java sampler extending the JMeter-AbstractJavaSamplerClient, overriding runTest() a.s.o. Within the runTest()-implementation I acquire a ReentrantLock and use it to lock the critical code block. The point is, that JMeter doesn´t seem to care about that lock and I simply don´t get why...if I debug my code via remote debugging using Eclipse I see that several threads step into the locked code at the same time, which shouldn´t be the case. I also tried the old fashioned way using synchronize for the complete runTest()-implementation, but that doesn´t work either.

Does anyone have a suggestion what needs to be changed? Or at least an explanation why this doesn´t work?

Thanks in advance!

Upvotes: 2

Views: 1992

Answers (3)

Mason Wong
Mason Wong

Reputation: 31

Another workaround is by compiling a simple java class compile it and put it into the {JMETER_HOME}\apache-jmeter-3.1\lib\ext\ folder.

import java.util.*;

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

Export it into a jar file using CMD

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

Place the file into {JMETER_HOME}\apache-jmeter-3.1\lib\ext\ folder.

Create a Test Action and add a JSR223 PreProcessor into the test plan Show Image

import java.util.concurrent.Semaphore;

Global.map.clear();

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

Create another Test Action and add a JSR223 PreProcessor into the test plan 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");

It should overcome the race condition as Semaphore is synchronized among thread groups.

Upvotes: 2

Patze
Patze

Reputation: 307

I finally got it running...I didn´t declare my Lock to be static...thus it was possible that several threads entered the critical code block.

Upvotes: 0

Dmitri T
Dmitri T

Reputation: 168247

There are 2 options on how you can work it around without having to write your own sampler.

  1. The easiest and the most straightforward workaround is using __threadNum function as a parameter to ID so each thread would operate its own ID
  2. Use Beanshell scripting for removing variable which is currently being used from scope to assure that no other thread will pick the same variable.

Any of Beanshell test elements (Sampler, Post Processor, Pre Processor, Assertion, etc.) provides access to something called vars which is shorthand for JMeterVariables class instance. So you should be able to use:

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

methods anywhere in your test.

See How to use BeanShell: JMeter's favorite built-in component guide for more details and kind of Beanshell cookbook.

Upvotes: 0

Related Questions