JMeter timers add pauses before samplers. Without them, every thread sends its next request the moment the last one returns, which no real user does. The Constant, Uniform Random, Gaussian Random and Poisson Random timers add think time; the Constant Throughput and Precise Throughput timers pace threads to a target rate; the Synchronizing Timer holds threads back and releases them together.
We ran eight of JMeter 5.6.3’s nine timers (all but the BeanShell Timer, which works like the JSR223 Timer) against a local test API and measured the pauses they produced. Most behaved as the component reference describes. Three results are worth knowing before you build a test: the Constant Throughput Timer counts samples, not iterations; the Poisson Random Timer is far less random than its name suggests; and a Synchronizing Timer can leave a test running forever at its end.
Key Takeaways
- A timer pauses before every sampler in its scope. With several timers in scope, JMeter adds up their delays and sleeps once. Put a think-time timer under one sampler, or each request in the iteration waits.
- For think time, use the Uniform or Gaussian Random Timer. The Poisson Random Timer with lambda 200 ms gave pauses between 179 and 241 ms, not the long tail of real users.
- The Constant Throughput Timer targets samples per minute across every sampler it covers. Two requests per iteration at 1,200 per minute means 600 iterations a minute.
- A throughput timer only slows threads down. Two threads on a 500 ms endpoint reached 242 samples a minute against a 600 target.
- The Synchronizing Timer needs a timeout. Without one, in a thread group that runs a set number of iterations, threads left over at the end wait forever.
What are the timers in JMeter?
A timer is an element that delays the samplers in its scope. JMeter 5.6 ships nine of them. Four add a fixed or random pause, two calculate the pause needed to reach a target throughput, one blocks threads until a group has gathered, and two run your own script and pause for the number of milliseconds it returns:
| Timer | What it does | Use it for |
|---|---|---|
| Constant Timer | Pauses for a fixed number of milliseconds | Simple, predictable think time |
| Uniform Random Timer | Pauses for an offset plus a random value up to a maximum, all values equally likely | Think time within a range |
| Gaussian Random Timer | Pauses for an offset plus a normally distributed value | Think time clustered around a typical value |
| Poisson Random Timer | Pauses for an offset plus a Poisson-distributed value | Rarely the right choice (see below) |
| Constant Throughput Timer | Pauses so threads send a target number of samples per minute | A steady request rate |
| Precise Throughput Timer | Releases threads on a random schedule that totals a target number of samples | Random arrivals at an exact average rate |
| Synchronizing Timer | Blocks threads until a set number are waiting, then releases them together | Spikes of simultaneous requests |
| JSR223 Timer | Runs a Groovy (or other) script and pauses for the value it returns | Any custom delay |
| BeanShell Timer | The same, in BeanShell | Old plans only; the manual recommends JSR223 with Groovy |
How do timers apply to samplers?
A timer runs before each sampler in its scope, never after it. A timer placed directly under a thread group delays every sampler in that thread group; a timer placed as a child of one sampler delays only that sampler. When several timers are in scope, JMeter asks each for its delay, adds them up and sleeps once for the total.
We measured both rules. One thread ran two requests per iteration with a 300 ms Constant Timer. With the timer under the thread group, an iteration took 611 ms, because each request waited 300 ms. With the timer under the first request, it took 307 ms and the second request started without a pause. A Constant Timer of 100 ms and a Uniform Random Timer of 0 to 100 ms in the same scope gave pauses of 108 to 200 ms, averaging 153.
Two more details from JMeter’s source and our runs. The pause is not part of the sample’s response time, so timers never inflate the numbers in your report. And in a thread group with a duration set, a pause that would run past the end stops the thread instead of sleeping. Our guide to the execution order of elements in JMeter covers where timers sit among pre-processors, samplers and assertions.
How do the Constant, Uniform, Gaussian and Poisson timers differ?
They differ in the shape of the pauses. The Constant Timer pauses for the same time every time. The Uniform Random Timer spreads pauses evenly between its offset and the offset plus its maximum. The Gaussian Random Timer clusters them around its offset. The Poisson Random Timer also clusters them, much more tightly than most people expect.
We ran each timer under one thread for 100 requests to an endpoint that answers instantly, and measured the gap between the end of one request and the start of the next:
| Timer and settings | Mean pause | Standard deviation | Shortest to longest |
|---|---|---|---|
| Constant, 300 ms | 303.9 ms | 1.7 ms | 300 to 309 ms |
| Uniform Random, offset 100, maximum 200 | 211.8 ms | 59.2 ms | 106 to 301 ms |
| Gaussian Random, offset 200, deviation 50 | 202.0 ms | 48.3 ms | 41 to 325 ms |
| Poisson Random, offset 0, lambda 200 | 202.8 ms | 12.9 ms | 179 to 241 ms |
The few milliseconds above each setting are JMeter’s own overhead on a busy laptop. The Gaussian timer’s deviation is a standard deviation, so about 95% of pauses fall within two deviations of the offset, and a few land well outside: our shortest was 41 ms. A large deviation next to a small offset would produce negative values; JMeter takes the absolute value, so they come back as positive pauses and the curve is no longer centred on the offset.
The Poisson result is the one to remember. A Poisson distribution with a mean of 200 has a standard deviation of only about 14, so the Poisson Random Timer behaves like a slightly noisy Constant Timer. It does not model random arrivals, which is a different, exponential distribution. The component reference itself points to the Precise Throughput Timer for Poisson arrivals.
How do you add realistic think time in JMeter?
Use a random timer under the request a user would pause before, sized from real data: the time users spend on a page in your analytics. The Uniform Random Timer is the simplest choice. When real pauses have a long tail, with many short ones and a few very long ones, a one-line JSR223 Timer in Groovy draws from an exponential distribution instead:
return (long) (-Math.log(1 - Math.random()) * 200)
Over 300 requests this gave a mean pause of 217.8 ms with a standard deviation of 211.5 ms, from 0 to 1,417 ms: the long tail the Poisson timer does not produce. Change 200 to the mean pause you want.
To scale think time without editing the plan, set the timer.factor property. With -Jtimer.factor=0.5, the Uniform Random Timer’s pauses halved to 53 to 152 ms, offset included, and the Poisson Random Timer’s to 90 to 124 ms. The Constant Timer ignored it and still paused for 300 ms. The factor applies to the Uniform, Gaussian and Poisson Random timers only. Where pauses should come from in the first place is covered in our guide to simulating realistic user behavior.
How does the JMeter Constant Throughput Timer work?
The Constant Throughput Timer works out how long each thread must wait so that the samplers it covers run at a target rate, set in samples per minute. Its “Calculate Throughput based on” setting decides whose samples count toward the target: each thread on its own, all active threads in the thread group, or all active threads in the test, with shared variants of the last two.
The mode changes the result more than any other setting. We ran 4 threads for 30 seconds with a target of 1,200 samples per minute, once in each mode:
| Calculate Throughput based on | Samples per minute | Samples per thread in 30 s |
|---|---|---|
| this thread only | 4,812 | 600 each |
| all active threads | 1,210 | 150 to 152 |
| all active threads in current thread group | 1,211 | 150 to 153 |
| all active threads (shared) | 1,204 | 150 each |
| all active threads in current thread group (shared) | 1,204 | 150 each |
“This thread only” applies the target to every thread, so 4 threads produced four times the target. The other four modes hit 1,200 within 1%, and the shared and non-shared variants gave almost the same spread across threads. In every mode, each thread’s first sample went out without waiting, so the first second held 2 to 4 extra samples.
The target counts samples, not iterations or transactions. With two requests per iteration, the same 1,200 target produced 1,210 samples a minute, so each request ran about 600 times a minute. Count every sampler under the timer when you set it. The Throughput Controller is a different element that sets how often a branch runs, which our guide to JMeter logic controllers covers.
Why does the Constant Throughput Timer not reach its target?
Because it can only add pauses. If the threads cannot send the target number of samples without any pause, the timer has nothing to remove, and the rate falls short. Two threads against an endpoint that takes 500 ms can send about 4 requests a second, so a target of 600 a minute gave 242. The same plan with the Precise Throughput Timer gave the same 242.
The fix is more threads. Each thread can send at most one request per response time, so you need at least the target rate multiplied by the response time: 10 requests a second at 500 ms needs 5 threads, plus headroom for slower responses under load. Spare threads do not raise the rate above the target, since the timer holds them back; they cost only memory on the load generator.
The timer also changes how ramp-up behaves. With 10 threads ramping up over 10 seconds and a target of 600 a minute, the rate was 8 to 13 requests a second from the first second, because the first threads ran faster to make up for the ones not yet started. The timer turned the ramp-up into a flat line. If you need the load to climb, raise the target over time with a variable or property, or use a thread group that schedules the rate, as described in our guide to JMeter thread groups.
Constant Throughput Timer vs Precise Throughput Timer
Both pace threads to a target rate; they differ in how the requests are spread. The Constant Throughput Timer spaces samples evenly. The Precise Throughput Timer builds a schedule of random arrivals at the start of the test, so requests come in uneven bursts and gaps, as they do from real users, while the total over the test matches the target.
We ran the Precise Throughput Timer with 20 threads and a target of 300 samples per 30 seconds. It produced exactly 300 samples. Per second, the count ranged from 4 to 20 with a standard deviation of 3.5, and 12% of requests started within 10 ms of the one before. In the mode runs above, its constant counterpart sent the same number every second after the first, a standard deviation of 0. Bursts like these are what find connection-pool and locking problems that an even rate hides.
Three settings and rules from the component reference:
- Test duration (seconds) tells the timer how long to plan for, so it can deliver throughput × duration samples: 300 of 300 in our main run, 102 of 100 in a short 10-second one. It does not stop the test.
- Random seed at 0 gives a different schedule each run. Any other value repeats it: two runs with seed 42 started their requests at the same offsets, within 8 ms.
- Placement: put the timer under the first sampler of the iteration, or under a dummy sampler at the start, so it releases each iteration once. The manual says it works best below 36,000 samples an hour, and that an Open Model Thread Group is often the better choice for a load profile.
How does the Synchronizing Timer create a spike?
It blocks each thread that reaches it until a set number of threads are waiting, then releases them all at once. That turns steady traffic into bursts of simultaneous requests, which is how you test what happens when many users press the same button together. Two settings control it: the number of users to group by, and a timeout in milliseconds.
With think time in the plan, it worked only when the pause came from something other than a timer. We ran 10 threads, 4 iterations each, grouped by 5, with a random 0 to 1,000 ms pause before the request. With the pause on a Flow Control Action placed before the request, and the Synchronizing Timer under the request, the 40 requests went out in 8 bursts of exactly 5, each burst within 5 ms. With the random pause as a timer under the request, beside the Synchronizing Timer, the bursts disappeared: 40 requests spread over 39 separate moments. JMeter collects every timer’s delay first, so the Synchronizing Timer released the group, and only then did each thread sleep its own random pause.
The timeout is not optional in practice. With the timeout at 0, which means wait forever, a group can only form if enough threads arrive. At the end of a test, threads that have finished their iterations leave, and the ones still running cannot make up a group:
| Threads, iterations, group size | Timeout | Result |
|---|---|---|
| 7 threads, 2 iterations, groups of 5 | 0 (wait forever) | Hung after 10 of 14 requests, until killed |
| 7 threads, 2 iterations, groups of 5 | 2,000 ms | Bursts of 5, 5 and 4; finished in about 2 seconds |
| 10 threads, 4 iterations, groups of 5 | 0 (wait forever) | Hung after 38 of 40 requests, for over 3 minutes |
The last row surprised us: 40 arrivals is an exact multiple of 5, yet two threads still waited. In JMeter 5.6.3’s source, the thread that completes a group resets the timer after the group is released, and any thread that has already arrived for the next group is let through without waiting. With an instant endpoint and no think time that happened here, so the arrivals stopped dividing by 5 and two threads were left at the end with nobody to group with. Set a timeout a little longer than the gap you expect between arrivals. The manual adds that the timer works within one JVM, so on several load generators each one forms its own groups. Our guide to concurrency testing covers what such bursts are good for.
Do JMeter timers work when the test runs in the cloud?
Yes. A timer is part of the test plan, so it pauses the same way on any machine that runs the plan. What changes is the number of machines. In JMeter’s distributed mode, each load generator runs its own full copy of the plan, so a throughput timer’s target and a Synchronizing Timer’s groups apply to each generator separately. Divide a throughput target by the number of generators.
LoadFocus runs uploaded JMeter test plans in the cloud from 25 regions. You upload the .jmx with its CSV data files and set virtual users, duration and ramp-up for each run; the product page lists timers among the parts that run as they do on your machine, and the think times and pacing in your script are kept. See JMeter load testing in the cloud.
Frequently Asked Questions
What is the difference between the Constant Timer and the Constant Throughput Timer?
The Constant Timer pauses for the same number of milliseconds before each sampler, whatever the server does. The throughput timer calculates a different pause each time so that the samplers it covers run at a target number of samples per minute. Use the first for think time and the second for a request rate.
Why is my JMeter throughput lower than the Constant Throughput Timer target?
Because the timer can only add pauses. If your threads cannot reach the target without any pause, the rate falls short. You need at least as many threads as the target rate in requests per second multiplied by the response time in seconds: 10 requests a second at 500 ms needs 5. Also check its ‘Calculate Throughput based on’ setting, and remember that the target counts every sample it covers, not iterations.
Where should I put a timer in a JMeter test plan?
Put a think-time timer as a child of the sampler that should wait, so it applies to that request only. A timer directly under the thread group applies before every sampler in it. Put a Precise Throughput Timer under the first sampler of the iteration, or under a dummy sampler placed first.
Does a JMeter timer add to the response time?
No. A timer’s pause happens before the sampler starts, and the sample’s response time covers only the request itself. Timers lower throughput by spacing requests out, but they do not change the response times in the report. A Transaction Controller can include timer time in its own sample if you tick its ‘Include duration of timer and pre-post processors in generated sample’ option.
What does the Synchronizing Timer do in JMeter?
It holds threads until a set number of them are waiting, then releases them at the same moment, creating a spike of simultaneous requests. Always set its timeout above zero. Otherwise, in a thread group that runs a set number of iterations, threads left over at the end can wait forever and the test never finishes.
Sources
- Timers, section 18.6 of the Apache JMeter User’s Manual, Component Reference: jmeter.apache.org/usermanual/component_reference.html, read 4 November 2026. The modes, the Precise Throughput Timer’s settings and placement advice, the 36,000 per hour note,
timer.factor, and the one-JVM limit of the Synchronizing Timer are from this page. - Distributed testing, each server runs the full test plan: Apache JMeter User’s Manual, Remote Testing, jmeter.apache.org/usermanual/remote-test.html, read 4 November 2026.
- How JMeter sums timer delays, applies
timer.factorand ends a thread whose pause would pass the scheduled end:JMeterThread.java, methoddelay, in the Apache JMeter source at tag rel/v5.6.3 (github.com/apache/jmeter), read 4 November 2026. - Constant Throughput Timer mode labels:
ConstantThroughputTimerResources.propertiesin JMeter 5.6.3. - LoadFocus JMeter runs: loadfocus.com/jmeter-load-testing, read 4 November 2026.
- Test runs: Apache JMeter 5.6.3 (official release, SHA-512 verified) in non-GUI mode on Java 11.0.19, against a local Node.js 23.11.1 test API with instant and 500 ms endpoints, on an Apple M1 Max, 4 November 2026. Pauses were measured from the results file as the gap between one request’s end and the next one’s start. Timings show patterns, not benchmarks.