The ConcurrentNavigableMap<K,V> Interface
A concurrent, sorted map is defined by the ConcurrentNavigableMap<K,V> interface that extends both the ConcurrentMap<K,V> and the NavigableMap<K,V> interfaces. It overrides the methods shown below from its superinterfaces. Details on these overridden methods can be found in the ConcurrentMap<K,V> interface (p. 1491) and in the NavigableMap<K,V> interface (§15.10, p. 845).
The ConcurrentSkipListMap<K,V> class is an efficient implementation of the Concurrent-NavigableMap<K,V> class. This implementation is based on a concurrent variant of a skip list that is organized as a hierarchy of linked lists with subsequences of elements that are sorted, allowing efficient traversal, but at the extra cost of insertions in the skip list.
interface ConcurrentNavigableMap<K,V> extends ConcurrentMap<K,V>,
NavigableMap<K,V>
NavigableSet<K> descendingKeySet()
ConcurrentNavigableMap<K,V> descendingMap()
Return a reverse-order NavigableSet view of the keys or a reverse-order Concur-rentNavigableMap of the entries contained in this map, respectively.
ConcurrentNavigableMap<K,V> headMap(K toKey)
ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive)
Return a view of the portion of this map whose keys are strictly less than toKey or are less than or equal to toKey, if inclusive is true is specified.
NavigableSet<K> keySet()
NavigableSet<K> navigableKeySet()
Return a NavigableSet view of the keys contained in this map. These methods are equivalent.
ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey)
ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive)
Return a view of the portion of this map whose keys range from fromKey, inclusive, to toKey, exclusive, or from fromKey to toKey, where inclusion of the interval keys is explicitly specified.
ConcurrentNavigableMap<K,V> tailMap(K fromKey)
ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
Return a view of the portion of this map whose keys are greater than or equal to fromKey, or are greater than or equal to fromKey, if inclusive is true is specified.
Example 23.19 illustrates using the ConcurrentHashMap<K,V> class. A frequency map is created for rolling a dice at (3) and (4). A reader, declared as diceResultsReader at (1), repeatedly creates a new key set of the map and prints its contents. A remover, declared as diceResultRemover at (2), continuously removes the entry for a random dice result from the map. Both the reader and the remover take a snooze after printing the contents and removing an entry, respectively. All threads terminate on being interrupted, as the shutdownNow() method will initiate cancellation of all tasks at (6).
One reader and two removers are submitted to the service executor at (5). The output shows that the map contents reflect correctly that entries are removed and printed concurrently.
Example 23.19 Using a Concurrent Map
package concurrent;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ConcurrentHashMapDemo {
private static ConcurrentHashMap<Integer, Long> map;
public static final int NUM_OF_THROWS = 1000;
private static Runnable diceResultsReader = () -> { // (1)
String threadName = Thread.currentThread().getName();
while (true) {
ConcurrentHashMap.KeySetView<Integer, Long> keySetView = map.keySet();
String output = “”;
for (Integer key : keySetView) {
Long value = map.get(key);
output += ” ” + “<” + key + “,” + value + “>”;
}
System.out.println(threadName + “: {” + output + ” }”);
ConcUtil.snooze(1000, TimeUnit.MILLISECONDS);
if (Thread.interrupted()) break;
}
};
private static Runnable diceResultRemover = () -> { // (2)
String threadName = Thread.currentThread().getName();
while (true) {
ConcUtil.snooze(500, TimeUnit.MILLISECONDS);
if (Thread.interrupted()) break;
Integer key = ThreadLocalRandom.current().nextInt(1, 7); // [1, 6]
Long value = map.remove(key);
if (value == null) continue;
String removedEntry = threadName + “: removed “
+ “<” + key + “,” + value + “>”;
System.out.println(removedEntry);
}
};
public static void main(String[] args) throws InterruptedException {
map = new ConcurrentHashMap<>(6); // (3)
new Random().ints(NUM_OF_THROWS, 1, 7) // (4)
.boxed()
.parallel()
.collect(Collectors.groupingByConcurrent(
Function.identity(),
() -> map,
Collectors.counting()));
ExecutorService exs = Executors.newFixedThreadPool(3);
try {
exs.submit(diceResultsReader); // (5)
exs.submit(diceResultRemover);
exs.submit(diceResultRemover);
ConcUtil.snooze(5, TimeUnit.SECONDS);
} finally {
exs.shutdownNow(); // (6)
}
}
}
Probable output from the program:
pool-1-thread-1: { <1,160> <2,159> <3,170> <4,178> <5,158> <6,175> }
pool-1-thread-2: removed <1,160>
pool-1-thread-3: removed <6,175>
pool-1-thread-2: removed <5,158>
pool-1-thread-1: { <2,159> <3,170> <4,178> }
pool-1-thread-2: removed <4,178>
pool-1-thread-1: { <2,159> <3,170> }
pool-1-thread-1: { <2,159> <3,170> }
pool-1-thread-2: removed <2,159>
pool-1-thread-1: { <3,170> }
pool-1-thread-2: removed <3,170>
pool-1-thread-1: java.lang.InterruptedException: sleep interrupted
pool-1-thread-2: java.lang.InterruptedException: sleep interrupted
pool-1-thread-3: java.lang.InterruptedException: sleep interrupted