A JMeter Thread Group holds a Constant Timer and one sampler under it holds another. What pause runs?
answer
- More than one timer can be in scope
- JMeter does not pick between them
- The manual uses the word sum
- One sleep, not several
basics
~20 sBoth timers are in that sampler's scope, so JMeter adds their delays together and sleeps once for the total before running it. Every other sampler in the Thread Group waits only for the Thread Group timer.
solid answer
~50 sTimers are hierarchical, so a sampler collects every timer on the path from itself up to the Test Plan. When more than one is in scope, JMeter does not pick one and it does not apply them at separate moments: it **sums** the delays and pauses once for that total before the sampler runs. A Thread Group timer of 500 ms plus a sampler-level timer of 200 ms gives that one sampler a 700 ms pause, while its siblings get 500 ms. This is exactly what the manual says — "JMeter takes the sum of the timers and pauses for that amount of time before executing the samplers to which the timers apply" — and it is what `JMeterThread.delay()` does, accumulating each timer's value into one total before a single sleep. Adding a timer never replaces an inherited one; it only ever adds.
code
text · 5 linesThread Group
├─ Constant Timer Thread Delay = 500
├─ HTTP Request "Browse" -> pauses 500 ms
└─ HTTP Request "Checkout" -> pauses 700 ms
└─ Constant Timer Thread Delay = 200go deeper
Remember that a timer applies to every sampler under its parent and that a second timer in scope adds to the first rather than replacing it. Do not reason from the timer's line position.
Explain the collection step: the sampler gathers every timer on its path to the Test Plan, the values are summed, and the thread sleeps once for the total before the sampler runs.
Diagnose the shape in a real plan: deepest-nested samplers pausing longest, achieved rate below what the visible timer predicts, and the fix being to move the shared timer down rather than to tune numbers.
Set the convention that a sampler is in the scope of at most one timer, so pacing is readable from the tree and no maintainer has to add invisible terms in their head.
## Timers are collected, not chosen A timer is one of JMeter's strictly hierarchical elements. When the engine compiles the test tree it walks from each sampler up through every ancestor and gathers every timer it finds into that sampler's package. Nothing in that walk deduplicates, prefers the nearest one, or lets an inner timer override an outer one. So for the tree below, the sampler `Checkout` is in the scope of two timers and every other sampler in the group is in the scope of one. ``` Thread Group ├─ Constant Timer (Thread Delay 500) ├─ HTTP Request "Browse" └─ HTTP Request "Checkout" └─ Constant Timer (Thread Delay 200) ``` ## The delays add up The manual is explicit: if you add more than one timer to a Thread Group, JMeter takes the **sum** of the timers and pauses for that amount before executing the samplers the timers apply to. The engine's `delay()` method loops over the timers in the sampler's package, accumulates each one's value into a running total, and then performs a **single** sleep of that total. There is no per-timer sleep and no ordering effect between them. The outcome for the tree above: | Sampler | Timers in scope | Pause before it | | --- | --- | --- | | Browse | Thread Group timer only | 500 ms | | Checkout | Thread Group timer + its own | 700 ms | That asymmetry is usually not what the author wanted. The intent behind adding a 200 ms timer under `Checkout` is normally "this one should pause 200 ms", not "this one should pause 700 ms". ## Two ways to get what you meant 1. **Move the shared timer down.** Attach it under a controller or under the specific samplers that should carry it, so no sampler ever inherits two. This keeps every pause visible next to the sampler it belongs to. 2. **Do the arithmetic deliberately.** Keep the inherited timer and set the local one to the *difference* you actually want. This is compact but fragile: change the Thread Group timer later and every local timer silently shifts. The first option is almost always the right one in a plan several people edit, because it removes the invisible term from the sum. ## Randomised timers sum too The rule is about the numbers each timer returns, not about which timer class produced them. A Uniform Random Timer and a Constant Timer in the same scope both contribute, so the sampler waits the constant delay plus a fresh draw from the random one, re-evaluated on every pass. Two random timers in scope give you the sum of two independent draws, which is a distribution nobody deliberately designed — another reason to keep exactly one timer per scope. ## Things that are easy to get wrong here - **"The nearest timer wins."** It does not. Config-style precedence, where an inner element overrides an outer one, does not apply to timers; they accumulate. - **"Disabling the sampler-level timer will restore the default pause."** It restores the Thread Group's 500 ms, which may or may not be the pause anyone intended. - **"A timer with no sampler under it still ticks."** Timers are only processed when there is a sampler to which they apply, so a timer parked under an empty controller does nothing. - **"Adding a timer to a Thread Group affects only requests after it."** Position among siblings is irrelevant for a hierarchical element; the whole group is in scope either way. ## Checking it in a real plan The fastest audit is structural rather than behavioural: for each sampler, count the timers on the path from it up to the Test Plan. Any count above one is either a deliberate sum somebody documented or a bug. Behaviourally, the symptom is a plan whose achieved rate is lower than the arithmetic on the visible timer predicts, and whose deepest-nested samplers are the slowest to come round — which is the shape you would expect when the deepest samplers have collected the most timers. One extra note on placement: because a timer is served before its sampler, the pause is charged to the sampler that follows it, not to the one that came before. If you want a gap that belongs to the end of a flow rather than to the start of the next request, put the timer under the sampler that should be delayed, and let the tree say so.
- How would you give one sampler a longer pause than its siblings without inheriting the group's timer as well?Take the timer off the Thread Group and attach it to the samplers or the controller that should carry it, so no sampler ends up with two in scope. If the shared timer has to stay, set the local one to the difference you want and write down why, because it silently changes whenever the shared value changes.
- Does a Uniform Random Timer in the same scope as a Constant Timer replace it or add to it?It adds. JMeter sums whatever value each timer in scope returns for this pass, so the sampler waits the constant delay plus a fresh random draw. Two random timers in scope give the sum of two independent draws, which is rarely a distribution anyone designed on purpose.
- What happens to a timer attached under a controller that contains no samplers?Nothing. Timers, assertions and pre- and post-processors are only processed when there is a sampler to which they apply, so a timer with no sampler beneath its parent never contributes a delay.
saying these in an interview costs you the question
- Says the nearest timer overrides the outer one
- Expects two separate pauses rather than one combined sleep
- Thinks a Thread Group timer only affects requests below it
- Assumes a random timer replaces a constant one in the same scope
- Believes a timer under an empty controller still pauses the thread