Wednesday, December 5, 2012

BlockingQueue in Java – ArrayBlockingQueue vs LinkedBlockingQueue Example program Tutorial

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

BlockingQueue example in Java ArrayBlockingQueue LinkedBlockingQueueBefore 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)


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


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: []


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

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

5 comments :

Anonymous said...

I think there is a typo in the following statement:

"take() method of BlockingQueue will block if Queue is empty and put() method of BlockingQueue will block if Queue is empty."

should be "put() method of BlockingQueue will block if Queue is full."


Javin @ transient vs volatile java said...

@Anonymous, That's Indeed typo. put() method blocks if BlockingQueue is full. Thanks for pointing it out.

Anonymous said...

How do you know if BlockingQueue is thread-safe and doesn't allow null elements? Did you ran any test?? Also it's worth mentioning that take() remove objects from head of the queue

Miller said...

I think most important difference between ArrayBlockingQueue and LinkedBlockingQueue is that former is bounded and later is unbounded. So use former, if you need bounded queue functionality otherwise simply use LinkedBlockingQueue.

Anonymous said...

Queue's can be major source of latency in multi-threading environment. Extensive use of Queue in low latency application can jeopardize your performance goal, as there is always contention. Minimize sharing data between threads, that should be end goal.

Post a Comment