Skip to main content

JMeter Thread Groups: Types, Settings and Real Runs

JMeter thread groups explained: standard, setUp, tearDown and Open Model groups, the five error actions, and an open model run with 1,732 threads at once.

JMeter Thread Groups: Types, Settings and Real Runs

A JMeter thread group is the element that decides how many virtual users run a test, how they start and how long they keep going. Every sampler in a test plan sits under one. JMeter ships four: the standard Thread Group, the setUp Thread Group that runs before it, the tearDown Thread Group that runs after it, and the Open Model Thread Group, which schedules a request rate instead of a user count.

This guide runs each of them in JMeter 5.6.2 against a small local API and shows what happened. Three results matter most: the main groups started about 3 seconds after a setUp login that took 255 ms, “Stop Test Now” turned 1 real error into 5, and an Open Model group scheduled past the server’s capacity sent 4,000 requests, ran up to 1,732 threads at once, and recorded 1,423 failures that were never server errors.

Key Takeaways

  • The standard Thread Group is a closed model: a fixed number of threads, each sending its next request only after the last one finishes. Use it to model a known number of users.
  • setUp groups run to completion before any main group starts, tearDown groups after all of them end. Main groups run in parallel unless “Run Thread Groups consecutively” is ticked on the Test Plan.
  • “Action to be taken after a Sampler error” changes your results: on the same failing endpoint, the five choices recorded 400, 380, 89, 23 and 16 samples.
  • The Open Model Thread Group (JMeter 5.5 and later, still marked experimental) holds an arrival rate whatever the response times. Past the server’s capacity it keeps adding threads.
  • It also interrupts every request still in flight when the schedule ends. End the schedule with a pause() or those interruptions are logged as errors.

What is a thread group in JMeter?

A thread group is a pool of virtual users that all run the same steps. Each thread is one user: it runs the samplers, controllers and timers under the group from top to bottom, then starts again until the loop count or duration is used up. A test plan can hold several groups, each with its own users and settings.

The groups JMeter 5.6 offers out of the box:

Thread groupWhat it controlsWhen to use it
Thread GroupNumber of threads, ramp-up, loops or durationMost tests: a known number of concurrent users
setUp Thread GroupSame settings, runs before every main groupLogging in, creating test data, warming caches
tearDown Thread GroupSame settings, runs after every main groupDeleting test data, final checks
Open Model Thread GroupA schedule of request rates over timePublic sites and APIs where arrivals do not wait for responses

Plugins add more, mostly for load shapes the standard group cannot draw, covered in their own section below.

What do the Thread Group settings do?

Five settings define a standard Thread Group: the number of threads, the ramp-up period, the loop count, an optional thread lifetime (duration and startup delay), and the action to take after a sampler error. Two checkboxes adjust it: “Same user on each iteration” and “Delay Thread creation until needed”.

  • Number of Threads is the number of virtual users.
  • Ramp-up Period is how long JMeter takes to start all of them. The first thread starts at once, so 10 threads over 100 seconds start 10 seconds apart and the last one at 90 seconds. Our ramp-up period guide measures this with 100 threads.
  • Loop Count is how many times each thread runs the steps. “Infinite” runs until the duration ends or someone stops the test.
  • Specify Thread lifetime sets a duration and a startup delay in seconds. With both a loop count and a duration, whichever ends first wins.
  • Same user on each iteration keeps cookies and cache between iterations (with a Cookie Manager and Cache Manager). Unticked, each iteration behaves like a new user and opens a new connection, which costs more CPU and memory.
  • Delay Thread creation until needed creates each thread only when its start time comes, instead of creating all of them at the start and making them wait.

One detail in the component reference catches people out: JMeter checks the duration only between samples. We gave 2 threads a 5-second duration against an endpoint that answers in 8 seconds. Both requests ran until 8.1 seconds and the test ended after about 9, because JMeter does not interrupt a sampler that is waiting for its response.

In what order do JMeter thread groups run?

setUp groups run first and must finish completely. Then every main Thread Group starts at the same moment and runs in parallel. When the last main thread ends, tearDown groups run. Ticking “Run Thread Groups consecutively” on the Test Plan changes only the middle step: main groups then run one after another, in tree order.

We built a plan with a setUp group that logs in, two main groups (Browse: 5 threads × 20 loops; Order: 3 threads × 10 loops, using the login token) and a tearDown group that calls a health check. Times are milliseconds from the start of the run:

GroupParallel (default)Consecutive
setUp: login0 to 2550 to 589
Browse3,223 to 4,4553,686 to 4,612
Order3,225 to 4,1194,629 to 5,214
tearDown: health check4,458 to 4,4595,233 to 5,234

The login request took 255 ms, yet the main groups started 3 seconds later. JMeter’s log showed why: “Waiting for all setup thread groups to exit”, then the setUp thread ending 3.4 seconds after it started. The thread was not done when its request was. A JSR223 post-processor written in Groovy ran after the login, and the first Groovy script in a JVM compiles slowly. A cut-down plan with the same setUp login but no Groovy script started its main group 0.8 seconds in. Main groups wait for the whole setUp thread, post-processors included.

How do you pass data from a setUp thread group to the main test?

Store the value as a JMeter property, then read it with __P(). JMeter variables belong to one thread, so a token extracted in a setUp thread is invisible to every other thread. Properties are shared by all threads in the JVM, which makes them the bridge between groups.

In the setUp group, extract the token with a JSON Extractor (variable token, path $.token), then copy it into a property with a JSR223 PostProcessor:

props.put('token', vars.get('token'))

In the main group, an HTTP Header Manager sends Authorization: Bearer ${__P(token)}. All 30 order requests in our run returned 201; the same endpoint answers 401 without the header. One shared token suits data that really is shared, such as an admin key or a seeded ID. When every virtual user needs its own session, log in inside the main group instead, wrapped in a Once Only Controller, and keep the token in a variable; our correlation guide covers extracting and reusing values per user.

What does “Action to be taken after a Sampler error” do?

It decides what a thread does when a sample fails, either because the request failed (HTTP 4xx or 5xx counts) or because an assertion failed. The five options are Continue, Start Next Thread Loop, Stop Thread, Stop Test and Stop Test Now. The choice changes how many samples you record, so it changes your results.

We ran 5 threads × 40 loops of two requests: one to an endpoint that returns a 500 on every tenth call, then one to a healthy endpoint. Without errors that is 400 samples:

ActionSamples recordedFailed samplesWhat happened
Continue40020Every planned request ran
Start Next Thread Loop38020After each failure, the healthy request in that loop was skipped
Stop Thread895Each thread quit at its own first failure
Stop Test231The whole test stopped after the first failure, letting running samples finish
Stop Test Now165The test stopped at once; 4 requests in flight were cut off

The last row is the one to watch. Stop Test Now interrupts running samplers, and JMeter records each interrupted request as a failure with Non HTTP response message: Socket closed. The server returned exactly one 500; the results show five errors. Use Continue for load tests, so one bad response does not end the run, and judge errors from the results afterwards. Use Stop Test in a smoke test where the first failure means the rest is pointless.

One more trap from these runs: JMeter appends to an existing results file. Our first round of these five runs reused file names from an earlier run, and the counts came out doubled. Pass -f to overwrite, as our non-GUI mode guide explains.

What is the Open Model Thread Group in JMeter?

The Open Model Thread Group, added in JMeter 5.5, starts new iterations at a rate you schedule, such as rate(100/sec) random_arrivals(20 sec), instead of keeping a fixed number of threads busy. It creates threads as arrivals need them. The component reference still marks it experimental and says it may change in future releases.

The schedule is a short text expression. rate() sets a rate, random_arrivals() holds or ramps between two rates for a duration, and pause() adds a gap with no new arrivals:

rate(0) random_arrivals(1 min) rate(100/sec) random_arrivals(5 min) rate(100/sec) random_arrivals(1 min) rate(0)

That ramps from 0 to 100 iterations a second over a minute, holds for five minutes, then ramps down. Arrivals are random, so the gaps between them vary around the target. A “Random Seed” field makes the timing repeatable between runs. The docs’ even_arrivals() is listed but not implemented yet.

Closed vs open model: what happens when the server slows down?

A closed model sends less when the server slows down, because its threads are stuck waiting. An open model keeps sending at the scheduled rate, so requests queue and response times grow until something gives. Real visitors to a public site behave like the open model: they do not wait for other people’s pages to load before arriving.

Our test API serves about 145 to 160 requests a second. We ran 20 seconds of three setups against one endpoint:

SetupRequests per secondMedian99th percentileMost threads at onceErrors
Thread Group, 20 threads145135 ms180 ms200
Open Model, rate(100/sec)10132 ms126 ms285
Open Model, rate(200/sec)200 sent (4,000 in 20 s)5,558 ms9,954 ms1,7321,423

With 20 threads the server stayed at its ceiling and the 99th percentile looked healthy at 180 ms, because the test could never send faster than responses came back. At 100 a second, under capacity, the open model needed at most 28 threads. At 200 a second it kept starting iterations on schedule while the server fell behind: 1,732 threads at once, medians above 5 seconds. That is what an overload looks like to users, and the closed model cannot show it.

Why does the Open Model Thread Group record errors at the end?

When its schedule ends, the group interrupts every thread that is still running, and each cut-off request is recorded as a failure with Socket closed. The component reference warns about this and suggests adding a pause at the end so threads can finish.

In our runs every one of the errors in the table above was an interruption, not a server error: 5 at 100 a second, and 1,423 at 200 a second, which was the whole backlog waiting in the server’s queue. We reran the 200 a second test with pause(30 sec) added:

rate(200/sec) random_arrivals(20 sec) pause(30 sec)

All 4,000 requests completed with 0 errors. The latency got worse, not better: median 6,610 ms and 99th percentile 13,443 ms, because the slowest requests were now measured to completion instead of cut short. Without the pause, the run reported both fake errors and flattering latency. Size the pause to the longest response you expect under overload.

Which plugin thread groups are worth knowing?

The Custom Thread Groups plugin from jmeter-plugins.org adds several. They predate the Open Model Thread Group and are still common in older test plans and job descriptions.

All three below install through the JMeter Plugins Manager.

  • Concurrency Thread Group keeps a target number of threads running, with ramp-up steps and a hold time. It does not create all threads up front, and its page calls it a replacement for the Stepping Thread Group.
  • Ultimate Thread Group takes a table of rows, each with a thread count, start delay, ramp-up, hold and shutdown time, so you can draw spikes and steps.
  • Arrivals Thread Group schedules “arrivals”, meaning iteration starts, and creates new threads when all existing ones are busy: the plugin route to an open model. Its page warns that a constant arrival rate means growing concurrency and offers a “Concurrency Limit” field as a safety valve.

JMeter’s built-in open model group covers most of what the Arrivals plugin does without a plugin, but it has no concurrency cap: our 200 a second run reached 1,732 concurrent threads unchecked. If the machine running JMeter is small, that matters.

How many threads can one JMeter machine run?

It depends on the test, the machine and the heap, not on a fixed limit. Every JMeter thread is an operating system thread with its own stack, and our 200 a second run held 1,732 of them at once on a laptop. Watch the load generator’s CPU and memory during the run; when it is saturated, the response times you record include JMeter’s own delays.

Our post on how many concurrent users JMeter can handle goes through the limits in more detail. When the test needs more threads than one machine can run cleanly, split the load across several machines. LoadFocus runs uploaded JMeter test plans on cloud machines in 25+ regions and spreads the threads across them. When you upload a plan, you set virtual users, duration and ramp-up for each run, and LoadFocus adjusts the thread groups in its copy of the script to match. Timers, assertions and JSR223 samplers run as they do on your machine; thread counts, duration and ramp-up come from the run settings. See JMeter load testing in the cloud.

Frequently Asked Questions

What is the difference between a thread group and a thread in JMeter?

A thread is one virtual user that runs the test steps and repeats them, while a thread group is the container that sets how many of those threads run, how quickly they start, how many times they loop or how long they run, and what each does after an error.

Can JMeter run multiple thread groups at the same time?

Yes. By default every main group in a test plan starts at the same moment and runs in parallel, after any setUp groups have finished. To run them one after another instead, tick “Run Thread Groups consecutively” on the Test Plan element.

What is a setUp Thread Group used for?

A setUp Thread Group runs before the main groups start, for work the test needs once: logging in, creating users or data through an API, or warming a cache. It behaves like any other group, and the main groups wait until all of its threads have finished, including their post-processors.

Does the tearDown Thread Group run if I stop the test?

Only after a graceful shutdown, such as the Shutdown command in the JMeter GUI, and only when “Run tearDown Thread Groups after shutdown of main threads” is ticked on the Test Plan. If the test is stopped abruptly, with the Stop command or the Stop Test Now error action, the tearDown groups do not run even with that option ticked.

What is the difference between the Thread Group and the Open Model Thread Group?

The standard Thread Group runs a fixed number of users, and each sends its next request only after the last one returns, so a slow server receives less load. The Open Model Thread Group starts new iterations at a scheduled rate whatever the response times, adding threads as needed, so a slow server receives the same load and the queue shows up in response times.

Sources

  • Thread Group, setUp and tearDown Thread Group, Open Model Thread Group and Test Plan options: Apache JMeter User’s Manual, Component Reference, sections 18.9.1, 18.9.2, 18.9.10 and 18.9.11, as shipped with JMeter 5.6.2 and at jmeter.apache.org/usermanual/component_reference.html, November 2026.
  • Open Model Thread Group added in 5.5, interruption of pending requests on test stop in 5.6: jmeter.apache.org/changes_history.html; JMeter 5.6.3 release notes (nothing that affects the runs here): jmeter.apache.org/changes.html, November 2026.
  • Concurrency, Ultimate, Stepping and Arrivals Thread Groups: jmeter-plugins.org/wiki, plugin pages, November 2026.
  • LoadFocus JMeter runs: loadfocus.com/jmeter-load-testing and the “Logs & JTL File Analysis” guide at loadfocus.com/docs, read 1 November 2026.
  • Test runs: Apache JMeter 5.6.2 in non-GUI mode on Java 17.0.20, against a local Node.js 23.11.1 test API (4 workers, 25 ms each) on an Apple M1 Max, 1 November 2026. Timings show patterns, not benchmarks.

Bogdan

Founder at LoadFocus

Bogdan builds and runs the tools this blog is about. He writes from what the products actually do in production, including the parts that break.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.