Timers — Constant, Gaussian, Uniform Random

8 min read

Without timers, JMeter sends requests as fast as the server responds. Each thread finishes one request and immediately starts the next — no pause, no breathing room, no resemblance to real user behaviour. The result is a test that maximises throughput numbers while producing results that are useless for capacity planning. Timers fix this.

What timers actually model

A timer represents the time a real user spends between actions: reading a page, filling out a form, making a decision. In performance testing, this is called think time.

Think time affects two things:

  1. Concurrency. With a 2-second think time and a 100ms request time, a VU is only actively sending a request for 5% of its time. The other 95% it is waiting. This means 100 VUs with 2s think time produce roughly the same request throughput as 5 VUs with no think time — even though the concurrency (simultaneous users) is very different.

  2. Server state. Real servers accumulate open sessions, active transactions, and cache state from concurrent users. Without think time, threads cycle through too quickly to build up this state. The test does not reflect the memory pressure, lock contention, or session management load of real concurrent users.

Timer placement and scope

JMeter timers apply before the next sampler in scope. Placement determines which requests the timer affects:

  • At Thread Group level: applies before every sampler in the Thread Group
  • Inside a controller: applies before every sampler within that controller's scope
  • As a child of a specific sampler: applies only before that sampler

Multiple timers in scope stack — their delays are summed. A Thread Group-level 500ms timer and a sampler-level 300ms timer together add 800ms before that sampler.

Constant Timer

Adds the same fixed delay before every request in scope.

Configuration: Thread Delay = 1000 (milliseconds).

Thread Group
├── HTTP Request — "GET /page"     ← Constant Timer fires 1000ms before this
├── Constant Timer (1000ms)        ← applies to all siblings below AND their children
└── HTTP Request — "POST /submit"  ← Constant Timer fires 1000ms before this too

Constant Timer is the right choice when you want predictable, controlled think time — for example, in a stress test where you want exactly 1 request per second per user and the response time is near-zero.

Uniform Random Timer

Adds a random delay that falls uniformly within a range.

Configuration:

  • Random Delay Maximum: 2000 (ms)
  • Constant Delay Offset: 1000 (ms)

Total delay = constant offset + random value between 0 and maximum. With the example above: between 1000ms and 3000ms, with equal probability across the range.

This is a reasonable default for think time in most tests — it introduces variation without the complexity of statistical distributions.

Gaussian Random Timer

Adds a delay drawn from a normal (bell curve) distribution.

Configuration:

  • Deviation: 500 (ms)
  • Constant Delay Offset: 2000 (ms)

The constant offset is the mean. The deviation controls the spread. With offset=2000 and deviation=500, approximately 68% of delays fall between 1500ms and 2500ms, and 95% between 1000ms and 3000ms.

Gaussian distribution is more realistic than uniform for user think time — most users take similar amounts of time, with fewer at the extremes.

Poisson Random Timer

Adds delays drawn from a Poisson distribution, which models the inter-arrival times of independent random events. Used in academic and specialist performance testing for queuing theory modelling. Less commonly needed in practice than Gaussian or Uniform.

Synchronizing Timer

Holds threads at a barrier until N threads have arrived, then releases all of them simultaneously. This simulates a thundering herd — all users hitting submit at the same moment.

Configuration: Number of Simulated Users to Group By = 50.

When 50 threads have reached the Synchronizing Timer, they all proceed at the same instant. This is useful for testing race conditions, flash sale scenarios, or any situation where simultaneous access is the specific concern.

Do not use Synchronizing Timer in regular load tests — the simultaneous burst is an intentional abnormality, not a realistic load pattern.

Throughput Shaping Timer (plugin)

The Throughput Shaping Timer, from the JMeter Plugins package, controls requests per second over time by adjusting the delay between requests dynamically.

Configuration: a schedule table with rows defining Start RPS, End RPS, and Duration. JMeter calculates the required think time to hit the target RPS and applies it automatically.

Example schedule:

Start RPSEnd RPSDuration
101060s
10100120s
100100300s
100060s

This gives you a flat warm-up at 10 RPS, a 2-minute ramp to 100 RPS, a 5-minute sustained load, and a controlled ramp-down — independent of thread count.

Throughput Shaping Timer is the most precise way to replicate a known traffic profile from production logs.

Think time guidelines by workload type

ScenarioRecommended timerTypical range
REST API integration (machine-to-machine)None, or Constant 100–500ms0–500ms
Mobile app background syncConstant Timer500ms–2s
Web browsing — page readsGaussian, mean 3–5s1–10s
Form filling, user inputGaussian, mean 5–15s3–30s
Flash sale / burst testSynchronizing TimerN/A (barrier)
Controlled RPS rampThroughput Shaping TimerAs defined

⚠️ Common mistakes

  • No think time in a load test. Without timers, JMeter maximises requests per second but the test does not model real concurrency. A 10-user test without think time at 100ms per request produces 100 RPS — the same as a 1-user test with no think time would at 100ms response time. Adding 2s think time changes the concurrency model entirely.
  • Adding a Constant Timer above samplers instead of below them. Timers apply to the next sibling or child sampler below them in the tree. A timer placed as the last element in a controller applies to nothing below it — it fires into empty space. Place timers before the sampler they should delay, or at the top of the Thread Group to apply to all samplers.
  • Using Synchronizing Timer for normal load tests. The simultaneous release of all held threads causes a spike that bears no resemblance to gradual user arrival. Use Synchronizing Timer only for intentional burst scenarios, not as a substitute for a proper ramp-up configuration.

🎯 Practice task

Add realistic think time to your test plan and observe the effect on throughput.

  1. Open first-test.jmx. Run it with 10 users, 10-second duration, no timers. Note the requests per second in the Summary Report.
  2. Add a Uniform Random Timer at Thread Group level: Constant Offset = 1000ms, Random Delay Maximum = 2000ms. Run again with the same settings. Note how RPS drops significantly.
  3. Replace it with a Gaussian Random Timer: Constant Delay Offset = 2000ms, Deviation = 500ms. Run again. Compare the RPS to the Uniform timer run.
  4. Add a Constant Timer as a child of one specific HTTP Request (not Thread Group level). Set it to 500ms. Confirm in View Results Tree that only that specific sampler has the added delay — the other samplers run without it.
  5. Calculate: with 10 users, a 100ms average response time, and your Gaussian timer at 2000ms mean, what is the theoretical maximum RPS? (Answer: 10 users ÷ 2.1 seconds per iteration ≈ 4.8 RPS.) Compare to what JMeter actually measured.

// tip to track lessons you complete and pick up where you left off across devices.