A bounded thread queue coordinates producers and consumers with a FIFO item order and a maximum count of waiting items. In Python, queue.Queue provides synchronized put and get operations; a full queue can block a producer or raise Full for a nonblocking attempt. Removing an item does not mark the task complete: a consumer calls task_done after processing, and join waits for that unfinished-task count to reach zero. This is an in-process concurrency primitive. It does not persist work, retry failed jobs, or provide a distributed acknowledgment protocol. Locking also changes latency under contention, so an O(1) endpoint storage operation is not a wall-clock completion guarantee.
Bounded thread queues: separate FIFO removal from task completion
Operational case
A repair dispatcher has two waiting slots, preloaded with J-47 and J-52. A nonblocking attempt to add J-61 reports backpressure instead of silently discarding a job. One worker processes the two queued jobs and acknowledges each after appending it to its local result list. The main thread waits for the unfinished count and then for the worker to exit. Only one consumer runs here, so result order matches FIFO. With several workers, dequeue order remains defined, but completion order can differ; callers must not assume the printed order would remain identical.
Working Python program
from queue import Full, Queue
from threading import Thread
repair_queue = Queue(maxsize=2)
repair_queue.put("J-47")
repair_queue.put("J-52")
try:
repair_queue.put_nowait("J-61")
except Full:
print("backpressure")
processed = []
def repair_worker():
for _ in range(2):
job_id = repair_queue.get()
try:
processed.append(job_id)
finally:
repair_queue.task_done()
worker = Thread(target=repair_worker)
worker.start()
repair_queue.join()
worker.join()
print(processed)Output
backpressure
['J-47', 'J-52']Time, space, and tradeoff
Queue capacity bounds waiting items at O(c) space for capacity c, excluding items already held by workers. Endpoint enqueue and dequeue use constant-time underlying operations in ordinary conditions, but lock acquisition and blocking waits have workload-dependent latency. The sample uses a known two-task count so the worker can exit; a long-running service needs a sentinel, cancellation, or shutdown contract. Calling task_done in a finally block prevents join from hanging, but it does not mean a failed job succeeded. A real worker must separately record failures and decide whether and how to retry.
Common Mistakes
- Do not treat get as an acknowledgment of successful processing.
- Do not read qsize and assume the next put or get cannot block.
- Do not mistake an in-process queue for durable delivery.
Connected lessons
- Stacks and Queues
- Data Structures
- Queues: preserve arrival order without front shifts
- Ring buffers: make capacity and overwrite rules explicit
- Stacks: last-in-first-out for reversible edits
- Projects
- Quizzes
Apply it: Project: own a maintenance index and work queue and Index and queue invariants.
Bounded queues: close, wake waiters, and drain accepted work extends this operational boundary.
