Java BlockingQueue
- Java BlockingQueue Tutorial Video
- BlockingQueue Implementations
- BlockingQueue Usage
- Java BlockingQueue Example
- add()
- offer()
- offer(long millis, TimeUnit timeUnit)
- put()
- take()
- poll()
- poll(long timeMillis, TimeUnit timeUnit)
- remove(Object o)
- peek()
- element()
- contains(Object o)
- drainTo(Collection dest)
- drainTo(Collection dest, int maxElements)
- size()
- remainingCapacity
Jakob Jenkov |
The Java BlockingQueue interface, java.util.concurrent.BlockingQueue
,
represents a queue which is thread safe to put elements into, and take elements out of from. In other words,
multiple threads can be inserting and taking elements concurrently from a Java BlockingQueue
,
without any concurrency issues arising.
The term blocking queue comes from the fact that
the Java BlockingQueue
is capable of blocking the threads that try to insert or take elements from the
queue. For instance, if a thread tries to take an element and there are none left in the queue, the thread can
be blocked until there is an element to take. Whether or not the calling thread is blocked depends on what
methods you call on the BlockingQueue
. The different methods are explained in more detail later.
This text will not discuss how to implement a BlockingQueue
in Java yourself. If you are interested
in that, I have a text on Blocking Queues in my
more theoretical Java Concurrency Tutorial.
Java BlockingQueue Tutorial Video
If you prefer video, I have a video version of this tutorial here: Java BlockingQueue Tutorial
BlockingQueue Implementations
Since BlockingQueue
is an interface, you need to use one of its implementations to use it.
The java.util.concurrent
package has the following implementations of the BlockingQueue
interface:
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- LinkedBlockingDeque
- LinkedTransferQueue
- PriorityBlockingQueue
- SynchronousQueue
Click the links in the list to read more about each implementation.
BlockingQueue Usage
A BlockingQueue
is typically used to have one thread produce objects, which
another thread consumes. Here is a diagram that illustrates this principle:
A BlockingQueue with one thread putting into it, and another thread taking from it. |
The producing thread will keep producing new objects and insert them into the BlockingQueue
,
until the queue reaches some upper bound on what it can contain. It's limit, in other words.
If the blocking queue reaches its upper limit, the producing thread is blocked while
trying to insert the new object. It remains blocked until a consuming thread takes an
object out of the queue.
The consuming thread keeps taking objects out of the BlockingQueue
to processes them.
If the consuming thread tries to take an object out of an empty queue, the consuming thread is
blocked until a producing thread puts an object into the queue.
BlockingQueue Methods
The Java BlockingQueue
interface has 4 different sets of methods for inserting, removing and examining
the elements in the queue. Each set of methods behaves differently in case the requested operation
cannot be carried out immediately. Here is a table of the methods:
Throws Exception | Special Value | Blocks | Times Out | |
Insert | add(o) |
offer(o) |
put(o) |
offer(o, timeout, timeunit) |
Remove | remove(o) |
poll() |
take() |
poll(timeout, timeunit) |
Examine | element() |
peek() |
|
|
The 4 different sets of behaviour means this:
- Throws Exception:
If the attempted operation is not possible immediately, an exception is thrown. - Special Value:
If the attempted operation is not possible immediately, a special value is returned (often true / false). - Blocks:
If the attempted operation is not possible immedidately, the method call blocks until it is. - Times Out:
If the attempted operation is not possible immedidately, the method call blocks until it is, but waits no longer than the given timeout. Returns a special value telling whether the operation succeeded or not (typically true / false).
It is not possible to insert null
into a BlockingQueue
. If you try to insert null, the
BlockingQueue
will throw a NullPointerException
.
It is also possible to access all the elements inside a BlockingQueue
, and not just the elements at the start and end.
For instance, say you have queued an object for processing, but your application decides to cancel it. You can then
call e.g. remove(o)
to remove a specific object in the queue. However, this is not done very efficiently,
so you should not use these Collection
methods unless you really have to.
Java BlockingQueue Example
Here is a Java BlockingQueue
example. The example uses the ArrayBlockingQueue
implementation of the BlockingQueue
interface.
First, the BlockingQueueExample
class which starts a Producer
and a Consumer
in separate threads. The Producer
inserts strings into a shared BlockingQueue
,
and the Consumer
takes them out.
public class BlockingQueueExample { public static void main(String[] args) throws Exception { BlockingQueue queue = new ArrayBlockingQueue(1024); Producer producer = new Producer(queue); Consumer consumer = new Consumer(queue); new Thread(producer).start(); new Thread(consumer).start(); Thread.sleep(4000); } }
Here is the Producer
class. Notice how it sleeps a second between each put()
call.
This will cause the Consumer
to block, while waiting for objects in the queue.
public class Producer implements Runnable{ protected BlockingQueue queue = null; public Producer(BlockingQueue queue) { this.queue = queue; } public void run() { try { queue.put("1"); Thread.sleep(1000); queue.put("2"); Thread.sleep(1000); queue.put("3"); } catch (InterruptedException e) { e.printStackTrace(); } } }
Here is the Consumer
class. It just takes out the objects from the queue,
and prints them to System.out
.
public class Consumer implements Runnable{ protected BlockingQueue queue = null; public Consumer(BlockingQueue queue) { this.queue = queue; } public void run() { try { System.out.println(queue.take()); System.out.println(queue.take()); System.out.println(queue.take()); } catch (InterruptedException e) { e.printStackTrace(); } } }
add()
The Java BlockingQueue add()
method will add the element passed as parameter to this method
if the BlockingQueue has space for it internally. If the BlockingQueue does not have space internally for this
new element, the add()
method throws an IllegalStateException.
offer()
The BlockingQueue offer()
method will add the element passed as parameter to this method
if the BlockingQueue has space for it internally. If the BlockingQueue does not have space internally for this
new element, the offer()
method return false
.
offer(long millis, TimeUnit timeUnit)
The BlockingQueue offer()
method exists in a version which takes a time out as parameter. This
version of the offer()
method will add the element passed as parameter if the BlockingQueue
has space for it internally, or space becomes available. If the BlockingQueue does not have or get
space internally for this new element within the time out, this version of the offer()
method returns false
.
put()
The BlockingQueue put()
method inserts the element into the BlockingQueue if it has space for
it internally. If the BlockingQueue does not have space for the new element, the put()
method will block the thread calling the put()
method until the BlockingQueue as space
internally for the new element.
take()
The Java BlockingQueue take()
method will remove the first element in the BlockingQueue.
If the BlockingQueue does not contain any elements, the take()
method will block the
thread calling take()
until an element is inserted into the BlockingQueue.
poll()
The BlockingQueue poll()
method will remove the first element in the BlockingQueue.
If the BlockingQueue does not contain any elements, the poll()
method will return null
.
poll(long timeMillis, TimeUnit timeUnit)
The BlockingQueue poll(long timeMillis, TimeUnit timeUnit)
method will remove the first element in the
BlockingQueue. If the BlockingQueue does not contain any elements, this version of the poll()
method
will wait for an element to become available for the given amount of time passed to it as parameter. If no element
becomes available within the given time out period, this method returns null
.
remove(Object o)
The BlockingQueue remove(Object o)
method will remove a single instance of the given element from the
lockingQueue, if that element exists in the BlockingQueue. The remove()
method will use the
o.equals(element)
to decide if the object o passed as parameter matches a given element in the
BlockingQueue. If the BlockingQueue contains more than one element matching the given o parameter, only
one of these elements will be removed from the BlockingQueue. The remove()
method will return
true
if an element was removed, and false
if not.
peek()
The BlockingQueue peek()
method will return the first element of the BlockingQueue without removing it.
If the BlockingQueue does not contain any elements, the peek()
method will return null
.
element()
The BlockingQueue element()
method will return the first element of the BlockingQueue without removing it.
If the BlockingQueue does not contain any elements, the element()
method will throw a
NoSuchElementException.
contains(Object o)
The BlockingQueue contains(Object o)
method will return true
if the BlockingQueue
contains an object matching the object passed as parameter to the contains()
method.
The Objects.equals(o, element)
statement is used to check if the parameter object o matches a given
element in the BlockingQueue. If an element is found matching the parameter object, this method returns
true
. If no matching element is found, false
is returned.
drainTo(Collection dest)
The drainTo(Collection dest)
method drains all the elements of the BlockingQueue into the given destination
Collection.
drainTo(Collection dest, int maxElements)
The drainTo(Collection dest, int maxElements)
drains up to maxElements
from the
BlockingQueue into the destination Collection.
size()
The BlockingQueue size()
method returns the number of elements stored in BlockingQueue.
remainingCapacity
The BlockingQueue remainingCapacity()
method returns the remaining (unused) capacity of
the BlockingQueue. The remaining capacity is calculated as full capacity minus the number of elements
stored in the BlockingQueue.
Tweet | |
Jakob Jenkov |