skip to content

Your JMeter checkout run goes quiet: a Synchronizing Timer set to 100 users never releases. What do you check?

level: seniorimportance: should knowfreq 42%

answer

  1. Count who can be there at once
  2. Compare it with the Thread Group's count
  3. One field decides whether waiting ever ends
  4. Its default value is the dangerous one

basics

~20 s

Check whether 100 threads can ever wait at that barrier together. With Timeout in milliseconds at 0 the barrier waits forever, so a group size above the Thread Group's thread count or threads that already finished will hang the run.

solid answer

~50 s

The Synchronizing Timer blocks on a `CyclicBarrier` sized by **Number of Simulated Users to Group by**, and with **Timeout in milliseconds** at `0` it waits indefinitely — the manual is explicit that the test will then "pause infinitely" and only a forced stop ends it. So the diagnosis is arithmetic: count the threads that can be at that barrier simultaneously. Common causes are a group size larger than the Thread Group's Number of Threads, a ramp-up long enough that early threads finish their loops before late ones start, a controller that routes only some threads through the timer, and a distributed run where the group size exceeds the threads on one engine, since the barrier is per JVM. The fix is a non-zero **Timeout in milliseconds**: on expiry the timer logs a warning and returns `0`, releasing the waiters.

code

xml · 5 lines
xml
<SyncTimer guiclass="TestBeanGUI" testclass="SyncTimer" testname="Checkout barrier" enabled="true">
  <intProp name="groupSize">100</intProp>
  <longProp name="timeoutInMs">30000</longProp>
</SyncTimer>
<hashTree/>

go deeper

for a junior

Know that this timer blocks until enough threads are waiting, and that leaving Timeout in milliseconds at 0 means it waits forever. That alone explains most stalled runs.

for a middle

Explain the arithmetic of arrivals: group size against the Thread Group's Number of Threads, ramp-up and Loop Count interaction, and what a non-zero timeout changes when it expires.

for a senior

Diagnose from evidence. Take a thread dump, read jmeter.log for the timeout warning, enumerate every reason a thread might never reach the barrier, then choose between lowering the group size and adding a timeout.

for a principal

Make the safe default a policy: barriers carry a timeout, and group sizes are derived from the Thread Group rather than typed by hand, so a plan cannot be edited into a run that silently produces nothing.

## First establish that it is the barrier A stalled Synchronizing Timer looks like a healthy JVM doing nothing: threads alive, no samples arriving, no errors in `jmeter.log`. Two cheap confirmations: 1. **Take a thread dump.** Blocked threads sit in `SyncTimer.delay` inside `CyclicBarrier.await`, which names the cause outright. 2. **Check whether a timeout was configured.** If **Timeout in milliseconds** is non-zero and the barrier had expired, `jmeter.log` would carry the warning `SyncTimer <name> timeouted waiting for users after: <n>ms`. Its absence with a non-zero timeout means the threads have not reached the barrier at all. ## Then count the threads that can arrive The barrier opens only when exactly as many threads as the group size are waiting at once. Work through the ways that count can fall short: - **Group size above the Thread Group's Number of Threads.** Nothing validates the field against the group; 100 in a 50-thread group can never fill. This is the single most common cause. - **Ramp-up outlives the early threads.** With a long ramp-up the first threads may exhaust their Loop Count and exit before the last threads start. Threads that have finished never arrive. - **The timer is not on every thread's path.** An If Controller, a Switch Controller or a Once Only Controller above the timer means only some threads reach it. - **Sampler errors divert threads.** A Thread Group whose error action is *Stop Thread* quietly removes threads from the pool of possible arrivals. - **The run is distributed.** The barrier is a plain in-process `CyclicBarrier`, so it coordinates only the threads inside one JMeter JVM; a group size chosen for the whole fleet cannot fill on a single engine. ## Then fix it deliberately | Change | What it buys | What it costs | |---|---|---| | Set Timeout in milliseconds above 0 | the run always makes progress; a warning names the timer | groups may release under-filled, so the burst is smaller than intended | | Lower the group size below Number of Threads | the barrier fills in packs and keeps cycling | you no longer get one all-threads release | | Shorten the ramp-up | more threads are alive at the same moment | changes how the run starts | | Raise Loop Count or use the scheduler | threads stay alive long enough to arrive | lengthens the run | A non-zero timeout is the safety net worth having in almost every plan. On expiry `SyncTimer` catches the `TimeoutException`, logs the warning and returns `0`, so the waiting threads carry on rather than the run wedging. Two related behaviours are worth knowing: a **negative** timeout is not tolerated at all — `delay()` throws `IllegalArgumentException` naming the timer — and even a timeout of `0` is passed through `TimerService.adjustDelay`, which shortens the wait so it cannot outlast a scheduled end time. That is why a scheduled Thread Group eventually unblocks where an unscheduled one does not. ## Prove the fix After changing the timer, re-run and confirm three things: 1. Requests resume, and the results file shows the grouped samples starting at the same instant. 2. `jmeter.log` carries no `timeouted waiting for users` warning, or carries it only where you expect an under-filled group. 3. The number of threads that actually arrive matches the group size — if it does not, the timeout is masking the original miscount rather than curing it. ## The habit to carry away Treat the group size as a claim about the plan that must be checked against the Thread Group, the controllers above the timer and the number of engines in the run. Then set a timeout anyway, because the failure mode of getting it wrong is a run that produces nothing at all rather than a run that produces a slightly wrong number.

  • What exactly happens when a Synchronizing Timer's Timeout in milliseconds expires?
    The barrier await throws a TimeoutException, which SyncTimer catches. It logs a warning naming the timer and the timeout, returns a delay of 0 so the thread proceeds, and resets the barrier so the next group can form. The under-filled group is released, not failed.
  • Why can a scheduled Thread Group escape a stuck barrier when an unscheduled one cannot?
    Even a timeout of 0 is routed through TimerService.adjustDelay, which shortens any wait that would run past the thread's scheduled end time. With no scheduler there is no end time to clamp against, so the wait really is unbounded.
  • How would you tell a stuck barrier apart from a system under test that has simply stopped responding?
    A thread dump settles it. Barrier waits sit in SyncTimer.delay inside CyclicBarrier.await, while a stalled system leaves threads in socket reads inside the sampler. The results file helps too: a barrier stall produces no in-flight samples at all, whereas a slow system produces samples that eventually time out.

It behaves like a boarding gate that will not open until every named passenger has checked in. One no-show holds the whole flight indefinitely, which is exactly why the gate needs a departure time as well as a passenger list.

saying these in an interview costs you the question

  • Blames the system under test without taking a thread dump.
  • Says the timer times out by default, so waiting must be elsewhere.
  • Sets the group size above the Thread Group's thread count.
  • Expects a barrier in one engine to count threads on another.
  • Thinks a timeout expiry fails the run instead of releasing the group.