First-in-first out concurrent data structure having following characteristics:
- Before adding an item to the queue, waits for any operation to complete that could make the space available for this new item to be inserted in the queue.
- Waits for an item to put in the queue before allowing other methods to take an item from queue.
- Provides efficient thread-safety
- Provides integration with Java thread pools
BlockingQueue is used when there is one thread producing an object and another thread that consumes this object. Figure 20-1 shows this usage of BlockingQueue in action and looking at the figure the characteristics mentioned about BlockingQueue will become clearer.
Figure 20-1. Usage of BlockingQueue
The producing thread in this case keeps on producing the objects and sends it to the data structure and the consuming threads keeps consuming it. If the limit of the queue is reached, the producing thread will be blocked until the consuming thread consumes it making the space available for the producing thread to place the object in the queue. Similarly, if the consuming thread tries to take an obect from the empty queue, it is blocked until the producing thread places the object in the queue.
There are number of implementations for this BlockingQueue interface in the java.util.concurrent package, including the following:
Explanation of all these implementations will be too much to cover in this Chapter and I would suggest you read the Java API for more details. I mention of these classes mainly to give you an indication of the various implementations automatically supported by the Java language.
A BlockingDeque is a deque (Double Ended Queue) which waits to become non-empty before retrieving an element and waits for space to become available before storing an element.
BlockingDeque is used when the threads dealing with the queue are both producing and consuming the objects from the same queue. Figure 20-2 shows this usage of Blockingdeque in action and looking at the figure the characteristics mentioned about BlockingDeque will become clearer.
Figure 20-2. Usage of BlockingDeque
In the above case both the threads produces and consumes the objects inside the queue. If a thread inserts an object in the queue which is full, the inserting thread will be blocked until the consuming thread consumes the objects and frees the space in the queue. Similarly, if the queue is empty and the queue is empty, the thread consuming will be blocked until the producing thread puts some objects into the queue.
The BlockingDeque extends from BlockingQueue interface and there is only one implementation provided by Java in the form of LinkedBlockingDeque.
The java.util.concurrent package also hosts a concurrent map in the form of ConcurrentMap interface which extends from java.util.Map interface. It has some atomic methods in the form of “putIfAbsent”, “remove” and “replace”. In these map, the key-value pair is replaced or removed only if the key-value pair is present and the key-value pair is added only if it is not already present. This interface is a member of the Java Collections Framework.
ConcurrentHashMap is an implementation of this interface. ConcurrentHashMap is very much similar to HashMap offering much more concurrency. In achieving concurrency, while inserting or deleting, it doesn’t lock the entire collection, rather it only locks the part of the collection undergoing change. Another important difference between the two is that ConcurrentHashMap doesn’t throw ConcurrentModificationException when the map is being changed while being iterated. However, like Hashtable and unlike HashMap it doesn’t allow inserting null as key or value. This Class is also the member of Java Collections Framework.
It is sub-interface of ConcurrentMap. The general-purpose implementation of this interface is ConcurrentSkipListMap. ConcurrentSkipListMap is a scalable concurrent ConcurrentNavigableMap implementation. It is concurrent analog of TreeMap. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used. This class is also a member of Java Collections Framework.
A lock is a tool for controlling access to a shared resource by multiple threads. A Lock is a thread synchronization mechanism just like synchronized blocks. However a Lock is more flexible and sophisticated than a synchronized block. More sophisticated locking mechanisms are supported by the java.util.concurrent.locks package. The most prominent interface in this package is java.util.concurrent.locks.Lock. Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated “Condition” objects.
The biggest advantage of Lock objects over implicit locks is their ability to back out of an attempt to acquire a lock. The “tryLock” method backs out if the lock is not available immediately or before a timeout expires (if specified). The “lockInterruptibly” method backs out if another thread sends an interrupt before the lock is acquired. The implementation of Lock interface is java.util.concurrent.locks.ReentrantLock.
A java.util.concurrent.locks.ReadWriteLock is an advanced thread lock mechanism. It allows multiple threads to read a certain resource, but only one to write it, at a time. The concurrency error first occur when reads and writes to a shared resource occur concurrently, or if multiple writes take place concurrently. The implementation of ReadWriteLock interface is java.util.concurrent.locks.ReentrantReadWriteLock.
Page Visitors: 24422