A BlockingQueue in Java is a specialized queue that provides blocking functionality when inserting or retrieving elements. It is designed to be used primarily for producer-consumer queues, where one or more threads produce elements and one or more threads consume those elements.
Key Characteristics of BlockingQueue
- Thread-Safe: BlockingQueue implementations are thread-safe. All queuing methods are atomic in nature and use internal locks or other forms of concurrency control.
- Blocking Operations: When attempting to insert an element into a full queue or retrieve an element from an empty queue, the calling thread is blocked until the operation can be performed or the thread is interrupted.
- No Null Elements: BlockingQueue implementations do not accept null elements. Attempting to add a null element will result in a NullPointerException.
- Implementations: Java provides several BlockingQueue implementations, including:
- ArrayBlockingQueue: A bounded BlockingQueue backed by an array.
- LinkedBlockingQueue: An optionally bounded BlockingQueue based on linked nodes.
- PriorityBlockingQueue: An unbounded BlockingQueue that uses the same ordering rules as class PriorityQueue.
- SynchronousQueue: A simple BlockingQueue in which each insert operation must wait for a corresponding remove operation, and vice versa.
Methods of BlockingQueue
BlockingQueue provides four sets of methods for inserting, removing, and examining elements:
- Throws Exception: These methods throw an exception when the requested operation cannot be performed immediately.
- Special Value: These methods return a special value (often true/false) when the requested operation cannot be performed immediately.
- Blocks: These methods block the current thread indefinitely until the requested operation can succeed.
- Times Out: These methods block for only a specified maximum time limit and return a special value indicating whether the requested operation succeeded or timed out.
Here’s an example of using a BlockingQueue:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// Producer thread
new Thread(() -> {
try {
queue.put("message");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// Consumer thread
new Thread(() -> {
try {
String message = queue.take();
System.out.println(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
In this example, a producer thread adds a message to the queue using put()
, and a consumer thread retrieves the message using take()
. If the queue is full when the producer tries to add an element or empty when the consumer tries to retrieve an element, the respective thread is blocked until the operation can be performed.