BlockingQueue in Java is added in Java 1.5
along with various other concurrent Utility classes like ConcurrentHashMap,
Counting
Semaphore, CopyOnWriteArrrayList
etc. BlockingQueue is a unique collection type which not only store
elements but also supports flow control by introducing blocking if either
BlockingQueue is full or empty. take() method of BlockingQueue
will block if Queue is empty and put() method of BlockingQueue will block
if Queue is full. This property makes BlockingQueue an ideal choice for
implementing Producer
consumer design pattern where one thread insert element into BlockingQueue
and other thread consumes it. In this Java tutorial we will learn about What is
BlockingQueue in Java, How to use BlockingQueue, ArrayBlockingQueue and LinkedBlockingQueue and some
important properties of it.
Important properties of BlockingQueue in Java
Before using any new Collection class e.g. BlockingQueue, I always
read there API documentation to know more about it. There are always some
important points which is worth remembering and avoids potential programming
errors while using new Collection class. Following list of points about BlockingQueue in Java
will help to learn and understand more about it.
1) BlockingQueue in Java doesn't allow null
elements, various implementation of BlockingQueue like ArrayBlockingQueue, LinkedBlockingQueue throws NullPointerException
when you try to add null on queue.
BlockingQueue<String> bQueue = new ArrayBlockingQueue<String>(10);
//bQueue.put(null); //NullPointerException - BlockingQueue in Java doesn't allow null
bQueue = new LinkedBlockingQueue<String>();
bQueue.put(null);
Exception in thread "main" java.lang.NullPointerException
at java.util.concurrent.LinkedBlockingQueue.put(LinkedBlockingQueue.java:288)
//bQueue.put(null); //NullPointerException - BlockingQueue in Java doesn't allow null
bQueue = new LinkedBlockingQueue<String>();
bQueue.put(null);
Exception in thread "main" java.lang.NullPointerException
at java.util.concurrent.LinkedBlockingQueue.put(LinkedBlockingQueue.java:288)
2) BlockingQueue can be bounded or unbounded. A
bounded BlockingQueue is one which is initialized with
initial capacity and call to put() will be blocked if BlockingQueue is full
and size is equal to capacity. This bounding nature makes it ideal to use a
shared queue between multiple threads like in most common Producer
consumer solutions in Java. An unbounded Queue is one which is initialized
without capacity, actually by default it initialized with Integer.MAX_VALUE. most
common example of BlockingQueue uses bounded BlockingQueue as shown
in below example.
BlockingQueue<String> bQueue = new ArrayBlockingQueue<String>(2);
bQueue.put("Java");
System.out.println("Item 1 inserted into BlockingQueue");
bQueue.put("JDK");
System.out.println("Item 2 is inserted on BlockingQueue");
bQueue.put("J2SE");
System.out.println("Done");
Output:
Item 1 inserted into BlockingQueue
Item 2 is inserted on BlockingQueue
bQueue.put("Java");
System.out.println("Item 1 inserted into BlockingQueue");
bQueue.put("JDK");
System.out.println("Item 2 is inserted on BlockingQueue");
bQueue.put("J2SE");
System.out.println("Done");
Output:
Item 1 inserted into BlockingQueue
Item 2 is inserted on BlockingQueue
This code will only insert Java and JDK into BlockingQueue and then
it will block while inserting 3rd element J2SE because size of BlockingQueue is 2 here.
3)BlockingQueue implementations like ArrayBlockingQueue, LinkedBlockingQueue and PriorityBlockingQueue are thread-safe.
All queuing method uses concurrency control and internal locks to perform
operation atomically. Since BlockingQueue also
extend Collection, bulk Collection operations like addAll(), containsAll() are not
performed atomically until any BlockingQueue
implementation specifically supports it. So call to addAll() may fail
after inserting couple of elements.
4) Common methods of BlockingQueue is are put() and take() which are blocking
methods in Java and used to insert and retrive elements from BlockingQueue in Java. put() will block
if BlockingQueue is full and take() will block
if BlockingQueue is empty, call to take() removes
element from head of Queue as shown in following example:
BlockingQueue<String> bQueue = new ArrayBlockingQueue<String>(2);
bQueue.put("Java"); //insert object into BlockingQueue
System.out.println("BlockingQueue after put: " + bQueue);
bQueue.take(); //retrieve object from BlockingQueue in Java
System.out.println("BlockingQueue after take: " + bQueue);
Output:
BlockingQueue after put: [Java]
BlockingQueue after take: []
bQueue.put("Java"); //insert object into BlockingQueue
System.out.println("BlockingQueue after put: " + bQueue);
bQueue.take(); //retrieve object from BlockingQueue in Java
System.out.println("BlockingQueue after take: " + bQueue);
Output:
BlockingQueue after put: [Java]
BlockingQueue after take: []
5) BlockingQueue interface extends Collection, Queue and Iterable interface
which provides it all Collection and Queue related
methods like poll(), and peak(), unlike take(), peek() method
returns head of the queue without removing it, poll() also retrieves and removes elements from head but can wait till specified time if Queue is empty.
BlockingQueue<String> linkedBQueue = new LinkedBlockingQueue<String>(2);
linkedBQueue.put("Java"); //puts object into BlockingQueue
System.out.println("size of BlockingQueue before peek : " + linkedBQueue.size());
System.out.println("example of peek() in BlockingQueue: " + linkedBQueue.peek());
System.out.println("size of BlockingQueue after peek : " + linkedBQueue.size());
System.out.println("calling poll() on BlockingQueue: " + linkedBQueue.poll());
System.out.println("size of BlockingQueue after poll : " + linkedBQueue.size());
Output:
size of BlockingQueue before peek : 1
example of peek() in BlockingQueue: Java
size of BlockingQueue after peek : 1
calling poll() on BlockingQueue: Java
size of BlockingQueue after poll : 0
linkedBQueue.put("Java"); //puts object into BlockingQueue
System.out.println("size of BlockingQueue before peek : " + linkedBQueue.size());
System.out.println("example of peek() in BlockingQueue: " + linkedBQueue.peek());
System.out.println("size of BlockingQueue after peek : " + linkedBQueue.size());
System.out.println("calling poll() on BlockingQueue: " + linkedBQueue.poll());
System.out.println("size of BlockingQueue after poll : " + linkedBQueue.size());
Output:
size of BlockingQueue before peek : 1
example of peek() in BlockingQueue: Java
size of BlockingQueue after peek : 1
calling poll() on BlockingQueue: Java
size of BlockingQueue after poll : 0
6)Other important methods from BlockingQueue in Java is
remainingCapacity() and offer(), former returns number
remaining space in BlockingQueue, which can be filled without blocking
while later insert object into queue if possible and return true if success and
false if fail unlike add() method which throws
IllegalStateException if it fails to insert object into BlockingQueue. Use offer() over add() wherever
possible.
Usage
of BlockingQueue in Java
There can be many creative usage of BlockingQueue in Java
given its flow control ability. Two of the most common ways I see programmer
uses BlockingQueue is to implement Producer Consumer design pattern
and implementing Bounded buffer in Java. It surprisingly made coding and inter
thread communication over a shared object very easy.
ArrayBlockingQueue and LinkedBlockingQueue in Java
ArrayBlockingQueue and LinkedBlockingQueue are common
implementation of BlockingQueue<E> interface.
ArrayBlockingQueue is backed by array
and Queue impose orders as FIFO. head of the queue is
the oldest element in terms of time and tail of the queue is youngest element. ArrayBlockingQueue is also
fixed size bounded buffer on the other hand LinkedBlockingQueue is an
optionally bounded queue built on top of Linked nodes. In terms of throughput LinkedBlockingQueue provides
higher throughput than ArrayBlockingQueue in Java.
That’s all on What is BlockingQueue in Java and
How to use it. We have seen two convenient implementation of BlockingQueue i.e. ArrayBlockingQueue and LinkedBlockingQueue which
comes along with Java API. If you are implementing Producer
Consumer design pattern in Java, consider using BlockingQueue, it not only
make coding easy but also performs better and provide better robustness and
stability than writing your own BlockingQueue or using naked wait
and notify method.
Other Java Collection tutorials for Java developers
No comments:
Post a Comment