Concurrency Comparisons

Side-by-side trade-offs where neither column wins. The workload, the runtime and how much correctness risk you can carry decide — and each comparison ends with the verdict that follows from that, not from a preference.

Bounded vs unbounded queue

The bound is not a tuning parameter; it is where backpressure lives. An unbounded queue has not avoided the limit — it has moved the limit to available memory and the failure to a moment you did not choose.

DimensionBounded queueUnbounded queue
Behaviour when the consumer falls behindProducer blocks, drops or is rejected — you decideMemory grows until the process dies
BackpressureBuilt in: fullness is the signalNone — the producer never learns anything is wrong
Latency under overloadBounded by the queue lengthUnbounded — items age arbitrarily
Failure modeExplicit rejection or a blocked producerOOM, or delivering work whose result nobody wants any more
MemoryBounded and known in advanceWhatever the peak burst happened to be
Absorbs a short burstUp to the bound, then applies pressureYes — this is the one genuine advantage
Deadlock riskReal, if a producer is also a consumer of the same queueLower, since producers never block
DebuggabilityDepth and age are meaningful, comparable numbersDepth is just a number with no ceiling to compare against
Use Bounded queue when
  • Essentially every production pipeline.
  • You want overload to be a decision rather than an outcome.
  • Latency matters and stale work should be shed rather than served.
Use Unbounded queue when
  • Bursts are short, bounded by something external, and provably fit in memory.
  • The producer genuinely cannot block — an interrupt or signal context.
  • A prototype, with a follow-up ticket you will actually do.
Verdict

Bound it, and choose the overflow policy explicitly: block the producer, drop the oldest, drop the newest, or reject with an error the caller can act on. "It never gets that deep" is a statement about the traffic you have seen, not the traffic you will get.