Java protocol programming tips

When programming a Java Vuser script, you can paste ready-made code segments into scripts or import ready-made classes in order to invoke their methods. If Vusers need to run as threads under Controller (for scalability reasons), you need to make sure that all of the imported code is thread-safe.

Thread-safety is often difficult to detect. A Java Vuser may run flawlessly under VuGen and under Controller with a limited number of Vusers. However, problems may then occur with a large number of Vusers. Code that is not thread-safe is usually the result of static class member usage as shown in the following example:

import lrapi.*;
public class Actions
{
   private static int iteration_counter = 0;
    public int init() {
        return 0;
    }
    public int action() {
        iteration_counter++;
        return 0;
    }
    public int end() {
        lr.message("Number of Vuser iterations: "+iteration_counter);
        return 0;
    }
}

When you run one Vuser, the iteration_counter member determines the number of iterations that were executed. When multiple Vusers run together as threads on a single virtual machine, the static class member iteration_counter is shared by all threads, resulting in an incorrect counting. The total number of all Vusers iterations is counted.

If code is known to be non thread-safe and you still want to import it into your script, you can run the Vusers as processes. For more information on running Vusers as threads or processes, see Runtime settings.

When you run a basic Java Vuser script, it usually consists of a single thread—the main thread. Only the main thread can access the Java Vuser API. If a Java Vuser spawns secondary worker threads, using the Java API may cause unpredictable results. Therefore, we recommend that you use the Java Vuser API only in the main thread. Note that this limitation also affects the lr.enable_redirection function.

The following example illustrates where the LR API may and may not be used. The first log message in the execution log indicates that the value of flag is false. The virtual machine then spawns a new thread set_thread. This thread runs and sets flag to true, but does not issue a message to the log, even though the call to lr.message exists. The final log message indicates that the code inside the thread was executed and that flag was set to true.

boolean flag = false;
public int action() {
   lr.message("Flag value: "+flag);
   Thread set_thread = new Thread(new Runnable();{
        public void run() {
           lr.message("LR-API NOT working!");
           try {Thread.sleep(1000);} catch(Exception e) {}
           flag = true;
        }
   });
   set_thread.start();
   try {Thread.sleep(3000);} catch(Exception e) {}
   lr.message("Flag value: "+flag);
   return 0;
}

Note:  

Although .NET-based and Java protocols support creating threads, we recommend that you do not use background threads in real load testing scenarios because:

  • Threads can degrade tests scalability.

  • Threads can affect performance measurements.

  • The utility functions' behavior is undetermined if called from any thread except the Vuser main thread which runs the vuser_init, Action, and vuser_end actions. This applies to all functions named lr*.

Back to top