Class MultiKeyMap<V>
- Type Parameters:
V
- the type of values stored in the map
- All Implemented Interfaces:
ConcurrentMap<Object,
,V> Map<Object,
V>
MultiKeyMap allows storing and retrieving values using multiple keys. Unlike traditional maps that use a single key, this map can handle keys with any number of components, making it ideal for complex lookup scenarios.
Key Features:
- N-Dimensional Keys: Support for keys with any number of components (1, 2, 3, ... N).
- High Performance: Zero\-allocation polymorphic storage and optimized hash computation — no GC/heap used for "gets".
- Thread\-Safe: Lock\-free reads with auto\-tuned stripe locking that scales with your server, similar to ConcurrentHashMap.
- Map Interface Compatible: Supports single\-key operations via the standard Map interface (get()/put() automatically unpack Collections/Arrays (typed or Object[]) into multi\-keys).
- Flexible API: Var-args methods for convenient multi\-key operations (get()/put() with many keys).
- Smart Collection Handling: Configurable behavior for Collections and Arrays — change the default automatic unpacking of Collections/Arrays capability as needed.
Usage Examples:
// Create a multi-key map
MultiKeyMap<String> map = new MultiKeyMap<>(1024);
// Store values with different key dimensions using Map interface
map.put("single-key", "value1"); // 1D key
map.put(new Object[]{"k1", "k2"}, "value2"); // 2D key via array
map.put(Arrays.asList("k1", "k2", "k3"), "value3"); // 3D key via Collection
// OR use convenient varargs methods (requires MultiKeyMap variable type)
MultiKeyMap<String> mkMap = new MultiKeyMap<>();
mkMap.put("value1", "single-key"); // 1D key
mkMap.put("value2", "key1", "key2"); // 2D key
mkMap.put("value3", "key1", "key2", "key3"); // 3D key
mkMap.put("value4", "k1", "k2", "k3", "k4"); // 4D key
// ... unlimited dimensions
// Retrieve values using matching signatures
String val1 = map.get("single-key");
String val2 = map.get(new Object[]{"k1", "k2"});
String val3 = mkMap.get("key1", "key2");
String val4 = mkMap.get("k1", "k2", "k3", "k4");
Collection and Array Handling:
MultiKeyMap provides flexible handling of Collections and Arrays through the
MultiKeyMap.CollectionKeyMode
enum:
- MULTI_KEY_ONLY: Collections/Arrays are always unpacked into multi-key lookups
- MULTI_KEY_FIRST: Try unpacking first, fallback to treating as single key
- COLLECTION_KEY_FIRST: Try as single key first, fallback to unpacking
// Configure collection handling behavior
MultiKeyMap<String> map = new MultiKeyMap<>(1024, CollectionKeyMode.COLLECTION_KEY_FIRST);
String[] arrayKey = {"config", "database", "url"};
map.put(arrayKey, "jdbc:mysql://localhost:3306/db"); // Array treated as single key
String url = map.get(arrayKey); // Retrieved as single key
Performance Characteristics:
- Time Complexity: O(1) average case for get/put/remove operations
- Space Complexity: O(n) where n is the number of stored key-value pairs
- Memory Efficiency: Polymorphic storage (Object vs Object[]) eliminates wrappers
- Concurrency: Lock-free reads with auto-tuned stripe locking that scales with your server
- Load Factor: Configurable, defaults to 0.75 for optimal performance
Thread Safety:
This implementation is fully thread-safe with enterprise-grade concurrency. Read operations (get, containsKey, etc.) are completely lock-free for maximum throughput. Write operations use auto-tuned stripe locking that scales with your server's cores, enabling multiple concurrent writers to operate simultaneously without contention. The stripe count auto-adapts to system cores (cores/2, minimum 8) for optimal performance across different hardware. Global operations (resize, clear) use coordinated locking to prevent deadlock while maintaining data consistency.
- Author:
- John DeRegnaucourt ([email protected])
Copyright (c) Cedar Software LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
License
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enum
Enum to control how Collections and Arrays are handled in get/remove/containsKey operations.static enum
Enum to control how keys are stored in put() operations.static class
Represents a single entry in the MultiKeyMap. -
Constructor Summary
ConstructorsConstructorDescriptionCreates a new MultiKeyMap with default capacity (16) and default load factor (0.75).MultiKeyMap
(int capacity) Creates a new MultiKeyMap with the specified capacity and default load factor.MultiKeyMap
(int capacity, float loadFactor) Creates a new MultiKeyMap with the specified capacity and load factor.MultiKeyMap
(int capacity, float loadFactor, MultiKeyMap.CollectionKeyMode collectionKeyMode) Creates a new MultiKeyMap with specified capacity, load factor, and collection key behavior.MultiKeyMap
(MultiKeyMap.CollectionKeyMode collectionKeyMode) Creates a new MultiKeyMap with default capacity (16) and specified collection key behavior. -
Method Summary
Modifier and TypeMethodDescriptionvoid
clear()
Removes all the mappings from this map.computeIfAbsent
(Object key, Function<? super Object, ? extends V> mappingFunction) computeIfPresent
(Object key, BiFunction<? super Object, ? super V, ? extends V> remappingFunction) boolean
containsKey
(Object key) Map interface compatible containsKey method.boolean
containsKey
(Object... keys) Returns true if this map contains a mapping for the specified N-dimensional key.boolean
containsValue
(Object value) Returns true if this map maps one or more keys to the specified value.entries()
Returns an iterator over all entries in the map.entrySet()
Returns a Set view of the mappings contained in this map.boolean
Compares the specified object with this map for equality.Map interface compatible get method with zero-allocation direct storage.Gets the conversion function for the given N-dimensional key, or null if not found.double
Returns the current load factor.int
Returns the maximum chain length encountered so far.int
hashCode()
Returns the hash code value for this map.boolean
isEmpty()
Returns true if this map contains no key-value mappings.keySet()
Returns a Set view of the keys contained in this map.void
Prints detailed contention statistics for debugging performance issues.Map interface compatible put method with auto-unpacking for arrays.Premium var-args API - Store a value with unlimited multiple keys.void
putIfAbsent
(Object key, V value) Map interface compatible remove method with auto-unpacking for arrays and collections.Removes the mapping for the specified N-dimensional key from this map if it is present.boolean
boolean
int
size()
Returns the current number of entries in the map.toString()
Returns a string representation of this map.values()
Returns a Collection view of the values contained in this map.Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
Methods inherited from interface java.util.concurrent.ConcurrentMap
forEach, getOrDefault, replaceAll
-
Constructor Details
-
MultiKeyMap
public MultiKeyMap(int capacity, float loadFactor) Creates a new MultiKeyMap with the specified capacity and load factor.- Parameters:
capacity
- the initial capacityloadFactor
- the load factor threshold for resizing
-
MultiKeyMap
Creates a new MultiKeyMap with specified capacity, load factor, and collection key behavior.- Parameters:
capacity
- the initial capacityloadFactor
- the load factor threshold for resizingcollectionKeyMode
- how to handle Collections/Arrays in get/remove/containsKey operations
-
MultiKeyMap
public MultiKeyMap()Creates a new MultiKeyMap with default capacity (16) and default load factor (0.75). -
MultiKeyMap
Creates a new MultiKeyMap with default capacity (16) and specified collection key behavior.- Parameters:
collectionKeyMode
- how to handle Collections/Arrays in get/remove/containsKey operations
-
MultiKeyMap
public MultiKeyMap(int capacity) Creates a new MultiKeyMap with the specified capacity and default load factor.- Parameters:
capacity
- the initial capacity
-
-
Method Details
-
get
Gets the conversion function for the given N-dimensional key, or null if not found. This method is lock-free for maximum read performance.- Parameters:
keys
- the key components (can be varargs or Object[])- Returns:
- the value associated with the key, or null if not found
-
get
Map interface compatible get method with zero-allocation direct storage. Supports both single keys and N-dimensional keys via Object[] detection. -
put
Premium var-args API - Store a value with unlimited multiple keys. This is the recommended API for MultiKeyMap users as it provides the best developer experience with unlimited keys and zero array allocations for inline arguments.Examples:
MultiKeyMap<Employee> map = new MultiKeyMap<>(); // Zero allocation - no arrays created map.put(employee, "dept", "engineering", "senior"); map.put(person, "location", "building1", "floor2", "room101"); // Works with existing arrays too String[] keyArray = {"dept", "marketing", "director"}; map.put(manager, keyArray); // Passes array directly to varargs
- Parameters:
value
- the value to storekeys
- the key components (unlimited number)- Returns:
- the previous value associated with the key, or null if there was no mapping
-
put
Map interface compatible put method with auto-unpacking for arrays. This provides a great experience for Map users by automatically detecting and unpacking arrays into multi-key calls.Auto-unpacking behavior:
- If key is an array → automatically unpacked into multiple keys
- If key is a Collection → automatically unpacked into multiple keys
- Otherwise → treated as single key
Examples:
Map<Object, Employee> map = new MultiKeyMap<>(); // Auto-unpacking: array becomes multi-key String[] keys = {"dept", "engineering", "senior"}; map.put(keys, employee); // Stored as 3-key entry // Auto-unpacking: Collection becomes multi-key List<String> keyList = Arrays.asList("dept", "sales", "junior"); map.put(keyList, employee); // Stored as 3-key entry // Single key: other objects stored normally map.put("manager", boss); // Stored as single-key entry // Typed arrays also auto-unpack int[] intKeys = {1, 2, 3}; map.put(intKeys, data); // Stored as 3-key entry
-
size
public int size()Returns the current number of entries in the map. -
getMaxChainLength
public int getMaxChainLength()Returns the maximum chain length encountered so far. -
getLoadFactor
public double getLoadFactor()Returns the current load factor. -
entries
Returns an iterator over all entries in the map. The iterator captures a snapshot of the current state and is thread-safe for reads. Concurrent modifications during iteration may not be reflected in the iteration. -
isEmpty
public boolean isEmpty()Returns true if this map contains no key-value mappings. -
containsValue
Returns true if this map maps one or more keys to the specified value.- Specified by:
containsValue
in interfaceMap<Object,
V>
-
remove
Removes the mapping for the specified N-dimensional key from this map if it is present.- Parameters:
keys
- the key components (can be varargs)- Returns:
- the previous value associated with the key, or null if there was no mapping
-
remove
Map interface compatible remove method with auto-unpacking for arrays and collections. This provides a great experience for Map users by automatically detecting and unpacking arrays/collections into multi-key calls.Auto-unpacking behavior:
- If key is an array → automatically unpacked into multiple keys
- If key is a Collection → automatically unpacked into multiple keys
- Otherwise → treated as single key
Examples:
Map<Object, Employee> map = new MultiKeyMap<>(); // Auto-unpacking: array becomes multi-key String[] keys = {"dept", "engineering", "senior"}; Employee removed = map.remove(keys); // Removes 3-key entry // Auto-unpacking: Collection becomes multi-key List<String> keyList = Arrays.asList("dept", "sales", "junior"); Employee removed2 = map.remove(keyList); // Removes 3-key entry // Single key: other objects removed normally Employee manager = map.remove("manager"); // Removes single-key entry // Typed arrays also auto-unpack int[] intKeys = {1, 2, 3}; Data removed3 = map.remove(intKeys); // Removes 3-key entry
-
putAll
-
putIfAbsent
Uses a double-check locking pattern to avoid unnecessary synchronization when a value is already present. If the key is absent or currently mapped to
null
, the provided value is stored.- Specified by:
putIfAbsent
in interfaceConcurrentMap<Object,
V> - Specified by:
putIfAbsent
in interfaceMap<Object,
V> - See Also:
-
computeIfAbsent
Performs a double-check locking pattern to avoid unnecessary synchronization when the value already exists. If the value is absent or
null
, the mapping function is invoked and the result stored if non-null.- Specified by:
computeIfAbsent
in interfaceConcurrentMap<Object,
V> - Specified by:
computeIfAbsent
in interfaceMap<Object,
V> - See Also:
-
computeIfPresent
public V computeIfPresent(Object key, BiFunction<? super Object, ? super V, ? extends V> remappingFunction) Applies the remapping function if the specified key is present and currently mapped to a non-null value. The operation is performed under a single synchronization to ensure atomicity.
- Specified by:
computeIfPresent
in interfaceConcurrentMap<Object,
V> - Specified by:
computeIfPresent
in interfaceMap<Object,
V> - See Also:
-
compute
Computes a new mapping for the specified key using the given remapping function. The entire computation occurs while synchronized on the map's write lock to provide atomic behavior.
-
remove
-
replace
-
replace
-
merge
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null.
-
containsKey
Returns true if this map contains a mapping for the specified N-dimensional key.- Parameters:
keys
- the key components (can be varargs)- Returns:
- true if a mapping exists for the key
-
containsKey
Map interface compatible containsKey method. Supports both single keys and N-dimensional keys via Object[] detection. Uses efficient decision tree pattern: Normal objects first, then Arrays, then Collections.- Specified by:
containsKey
in interfaceMap<Object,
V> - Parameters:
key
- either a single key or an Object[] containing multiple keys- Returns:
- true if a mapping exists for the key
-
clear
public void clear()Removes all the mappings from this map. The map will be empty after this call returns. -
values
Returns a Collection view of the values contained in this map. The collection is backed by the map's current state snapshot. -
keySet
Returns a Set view of the keys contained in this map. For MultiKeyMap, keys can be single objects or Object[] arrays. The set is backed by the map's current state snapshot. -
entrySet
Returns a Set view of the mappings contained in this map. Each entry represents a key-value mapping where the key can be a single object or an Object[] array for multi-dimensional keys. -
hashCode
public int hashCode()Returns the hash code value for this map. The hash code is computed based on all key-value pairs. -
equals
Compares the specified object with this map for equality. Returns true if the given object is also a map and the two maps represent the same mappings. -
toString
Returns a string representation of this map. Shows the key-value mappings in the format {key1=value1, key2=value2}. Handles self-references to prevent infinite recursion. -
printContentionStatistics
public void printContentionStatistics()Prints detailed contention statistics for debugging performance issues. Shows overall contention rates, stripe-level distribution, and global lock usage.
-