Blocking Queue in Java

Overview
BlockingQueue in Java is a subinterface of Queue, which provides additional operations and it is useful in situations where the queue is empty or full of elements.
Blocking queue in Java is a subinterface of Queue where additional operations are provided and are useful for cases where a queue is either empty or full
Introduction to Java Blocking Queue
Now how does a Queue differs from a blocking queue you may wonder A blocking queue in Java is a queue that provides insert and remove operations that block or wait until they're performed, they're usually used in the Producer-Consumer frameworks
Producer and consumer frameworks are two different processes where the producer produces data continuously and that data is pushed into the buffer whereas the consumer consumes that data from the buffer
Let's visualize this,
-
Blocking queue in Java throws NullPointerException if we try to store a null value in the queue since it does not accept null values
-
Blocking queue in Java is also thread-safe. The queuing methods use internal locks or other forms of concurrency control and are also atomic in nature
-
The BlockingQueue interface in Java comes with various concurrent utility classes such as ConcurrentHashMap, Counting Semaphore, CopyOnWriteArrrayList
-
Blocking queue in Java supports flow control by introducing blocking if the blocking queue is full or empty.
-
Whenever we try to enqueue an element using a thread in a full queue, it's blocked until another thread makes space for it in the said queue by either dequeuing one or more elements or clearing the queue completely, this happens the same way when we try to delete from an empty queue and it gets blocked until another thread inserts an item
-
Java 5 comes with BlockingQueue implementations in the java.util.concurrent package.
-
As blocking queue in Java is an interface we cannot directly provide its instance and so there's a need for creating classes to implement it, some of those classes are
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingDeque
- LinkedBlockingQueue
- LinkedTransferQueue
- PriorityBlockingQueue
- SynchronousQueue
Blocking queue in Java is supposed to be a thread-safe collection which is why it's used the most in multi-threading operations.
Multithreading is an ability of an operating system to allow multiple users simultaneously without requiring multiple copies of the same program running on the computer
Declaration
Let's see how we can declare a BlockingQueue in Java
Here, E is the type of elements stored in the Collection.
The Hierarchy of BlockingQueue
BlockingQueue Implementing Classes
As we've read before how we cannot provide an instance of a blocking queue in Java since it's an interface, in order to utilize the blocking queue's functionality we make use of classes ( mentioned above) for implementing these, let's see how we can do that.
Firstly, let's import using a blocking queue.
Here, the implementing class is LinkedBlockingDeque which is an implementation of a linked list data structure. It can be optionally bounded by a constructor, for unspecified values and can be Integer.MAX_VALUE by default Nodes are added dynamically following the capacity constraints
The Syntax for Creating Objects
We can create blocking queue in Java objects using LinkedBlockingDeque
or
Let's see how we can create objects of BlockingQueue class using
BlockingQueue Types
The BlockingQueue are two types:
1. Unbounded Queue:
An unbounded queue is never blocked because it can grow with the addition of more elements which can happen by setting the capacity using Integer.MAX_VALUE
Syntax:
The aim of consumers being able to consume messages as soon as producers add messages to the queues is important when it comes to designing a producer-consumer program using an unbounded blocking queue in Java. If these needs are not fulfilled, memory can fill up and throw an OutOfMemory exception.
2. Bounded Queue: We create a queue by passing the capacity of the queue in the queues constructor, this is known as a bounded queue
Syntax:
We can create bounded queues by passing capacity to the constructor as an argument like:
Here we have created a blocking queue in Java where it's capacity is 10
For a producer to add an element to a queue that's full, it will have to block until space for the insertion of another element is possible, or else the operations will fail.
Bounded queues can come in handy for designing concurrent programs, when an element is inserted in a full queue the needed operations are paused until other consumers catch up to make some space in the queue
Let's implement BlockingQueue in Java.
Output
Methods of the BlockingQueue Interface
Firstly let's see how we can distinguish between a queue and blocking queue based on the methods they provide
Method | Description |
---|---|
add() | This method inserts an element to the blocking queue towards its end, it throws an exception once the queue is full |
element() | This method returns the head of blocking queue in java and throws an exception if it’s empty |
remove() | This method removes an element from the blocking queue in java and throws an exception if it’s empty |
offer() | This method inserts the specified element into the blocking queue in java towards the end, it returns false if the queue is full |
peek() | This method returns head of the blocking queue and returns null if the queue is empty |
poll() | This method removes an element from the blocking queue and returns null if the queue is empty. |
put() | This method inserts an element to the blocking queuein Java, it waits for the space to be avaliable for inserting an element, once the queue is full |
take() | this method removes and returns an element from the blocking queue. It waits for the queue has elements to be deleted if it's empty |
The Behavior of BlockingQueue Methods
Blocking queue in Java provides various methods for inserting, removing, and examining operations on each queue. If at any point in time the requested operations are not satisfied immediately these four sets of methods act differently
Throws Exception: If the operation that is requested is not satisfied an exception will be thrown Special value: If the operations are not satisfied immediately a special value is returned. Blocks: If the attempted operation remains unsatisfied the method call is blocked and it waits until execution Times out: Whether an operation is successful or not a special value is returned. method call blocks until the requested operation are succeeded, it doesn't wait any longer than the given timeout
Basic Operations
1. Adding Elements
Depending upon the type of structure we're using we can add elements into a LinkedBlockedDeque Add method is one of the most common methods, we can also use the addAll() method for adding an entire collection to LinkedBlockedDeque (which is a method of the Collection interface) To use deque as a queue, we can use add() and put()
2. Accessing Elements
We can access LinkedBlockingDeque elements using:
- contains() : This method checks if a string contains a sequence of characters and returns true if they exist.
- element(): This method returns an element at front of the container without removing it
- peek() : This method is used to fetch the first element of the stack where the retrieved element does not get deleted from the stack itself
- poll(): This method is used for retrieving the first element of the Queue
3. Deleting Elements
We can delete elements from LinkedBlockingDeque using remove()
We can delete elements from LinkedBlockingDeque using remove() Other methods like take() and poll() is also used to remove the first and last elements
- take() : This method is used to retrieve and remove the head of the queue, if the said queue is empty, the next element is added only once it's empty
- poll(): This method is used to fetch and remove the very first element of the queue
4. Iterating through the Elements
We create an iterator to iterate through elements in LinkedBlockingDeque and use methods of the iterable interface (the root of the collection framework of Java) to access elements. Here the next() method returns an element of any collection
Java BlockingQueue Examples
Message (payload)
It's a Java object that's produced and added to the queue Just a normal Java object that will be produced by the producer and added to the queue
Producer
The producer class creates messages and puts in in the queue.
Consumer
Consumer class processes the message from the queue and once the exit message is received it's terminated
Service
Once we create the BlockingQueue service for producers and consumers, it'll create the BlockingQueue with a fixed size and is shared with both the producers and consumers. This service will then start producer and consumer threads and exit.
Output
Conclusion
- A BlockingQueue has a remaining capacity after which it's not possible to insert any element without blocking
- Implementation related to the BlockingQueue is thread safe since they achieve their events using internal locks or different forms of concurrency control
- BlockingQueue does not accept null elements, upon adding null value elements it throws a NullPointerException
- BlockingQueue implementation is provided by Java 5 in java.util.concurrent package
- Bounded queues can come in handy for designing concurrent programs
- Blocking queue in Java supports flow control by introducing blocking
- As blocking queue in Java is an interface we cannot directly provide its instance and so there's a need for creating classes to implement it