Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java PriorityBlockingQueue: add an admission limit to an unbounded priority queue

Last updated: 5 Oct 20265 min read
tutorial
AdvancedBy AITrove Editorial

PriorityBlockingQueue orders retrieval by priority but is logically unbounded; its constructor argument is an initial capacity, not a maximum backlog.

Operational contract

The wrapper acquires one of 47 permits before offering a job and releases it when a worker takes that job. This bounds jobs waiting in the queue, not jobs already being processed by workers. The queue comparator orders priority descending and receipt ID ascending for a defined tie break. A failed offer releases the permit. The queue remains private so callers cannot bypass the gate with direct insertion or removal. A production service must also cap producer concurrency and define shutdown and task-failure handling.

Failure case

All 47 waiting slots are filled. A new receipt job is rejected immediately even though PriorityBlockingQueue itself would otherwise accept it and grow. A worker take releases one waiting slot.

Java code

Java
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.Semaphore;

public class BoundedPriorityReceiptInbox {
    public record Job(int priority, long receiptId) { }
    private final Semaphore waitingSlots = new Semaphore(47);
    private final PriorityBlockingQueue<Job> jobs = new PriorityBlockingQueue<>(47,
            Comparator.comparingInt(Job::priority).reversed()
                    .thenComparingLong(Job::receiptId));

    public boolean submit(Job job) {
        Objects.requireNonNull(job);
        if (!waitingSlots.tryAcquire()) return false;
        boolean added = false;
        try {
            added = jobs.offer(job);
            return added;
        } finally {
            if (!added) waitingSlots.release();
        }
    }

    public Job take() throws InterruptedException {
        Job job = jobs.take();
        waitingSlots.release();
        return job;
    }
}

Performance and ownership cost

Insertion and removal are O(log N) heap operations for N queued jobs, capped here at 47 by the permit gate. The gate uses O(1) extra state. Worker execution and producer tasks are outside this queue bound.

Common Mistakes

  • Do not treat initial capacity or remainingCapacity as a backlog cap.
  • Do not expose the underlying queue for bypass insertion or removal.
  • Do not forget that priority service can starve low-priority jobs even with bounded storage.

Connected lessons

java
concurrent collections
priorityblockingqueue-explicit-capacity
Storage details