ConcurrentMap
ConcurrentMap 是 Java 并发包中提供的一个接口,它继承了 java.util.Map 接口,专门用于支持高并发环境下的线程安全操作。ConcurrentMap 提供了一系列线程安全的方法,旨在解决在多线程环境下使用普通 Map 类型(如 HashMap)时可能出现的竞态条件和数据不一致问题。
 
ConcurrentMap 具有以下特点:
-  线程安全性: ConcurrentMap中的方法都是线程安全的,可以在多线程环境中安全地使用,无需额外的同步措施。
-  高并发性能: ConcurrentMap的设计目标是在高并发环境下提供高性能的操作,尤其适用于读多写少的场景。
-  原子性操作:提供了一系列原子性操作,如 putIfAbsent、remove等,这些操作在执行时不会被其他线程干扰。
常见实现
ConcurrentMap 接口有多种实现,其中最常见的是 ConcurrentHashMap。其他实现还包括 ConcurrentSkipListMap 等。
-  ConcurrentHashMap: - 在 Java 8 之前,ConcurrentHashMap使用了锁分段技术(segment-based locking),将哈希表分割成多个段,每个段有自己的锁,从而允许多个写入操作并发进行。
- 在 Java 8 中,ConcurrentHashMap采用了基于 CAS(Compare and Swap)操作的新实现,提供了更高的并发性能。
 
- 在 Java 8 之前,
-  ConcurrentSkipListMap:- 使用跳表(Skip List)作为底层数据结构,提供了有序的键值对存储,适合需要排序操作的场景。
 
方法
ConcurrentMap 接口提供了以下常用方法(除了一些 Map 基本方法):
-  V get(Object key):获取指定键对应的值,如果映射表中不存在该键,则返回 null。
-  V put(K key, V value):将指定键值对插入到映射表中,如果这个键已经存在,则用新值替换旧值,并返回旧值。如果插入一个 null 的键或值,则抛出NullPointerException。
-  putIfAbsent(K key, V value):如果指定的键(key)不存在,则将键值对插入到映射表中;如果键已经存在,则不进行插入操作,并返回原先的值。
-  boolean remove(Object key, Object value):如果指定的键值对存在,则从映射表中删除该键值对;否则不进行任何操作。
-  boolean replace(K key, V value):替换指定键的值,无论该键原来的值是什么,都会执行替换操作。
-  boolean replace(K key, V oldValue, V newValue):以原子方式将键值对由旧值替换为新值,即只有在该键原来的值和提供的旧值(oldValue)相等时,才会执行替换操作。。
-  int size():返回映射表中键值对的数量。
-  V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction):如果指定键没有关联值,将通过运行映射函数来计算一个新的值,并将该键关联到该计算值。
-  V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):如果指定键已经具有相关联的值,则通过运行重新映射函数来计算一个新值,并将该键关联到该值。在计算过程中,更新可能会顺便修改现有映射,从而避免了常见的条件费用。
-  V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):原子性的操作,它能够在并发环境中安全地更新或计算指定键的值。key:要更新或计算值的键。remappingFunction:用于更新或计算值的函数。remappingFunction是一个在并发操作中被调用的函数,它接受两个参数:当前键的值(如果存在)和当前键。通过这个函数,可以基于当前的值来计算新的值。remappingFunction的返回值将作为新的值存储在ConcurrentHashMap中,若返回 null,则会删除当前键。
-  void forEach(BiConsumer<? super K, ? super V> action):对映射表中的每个键值对执行给定的动作。
-  V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction):如果指定的键已存在,将其关联的值与给定的合并函数合并,如果不存在,则将其关联到给定值。
-  default V getOrDefault(Object key, V defaultValue):获取指定键的值,如果键不存在,则返回默认值。可以用于避免空指针异常。
ConcurrentNavigableMap
ConcurrentNavigableMap 是 Java 并发包中的一个接口,它扩展了 ConcurrentMap 接口,并支持导航(查找和遍历)的功能。它允许多个线程同时访问和修改映射表,同时提供了按照键排序的功能。
ConcurrentNavigableMap 实现了一种有序的键值映射表,可以使用键的自然顺序或自定义的比较器对键进行排序。这些特性使得其特别适用于需要按照键进行范围查找和迭代的情况。
ConcurrentNavigableMap 的常见实现类是 ConcurrentSkipListMap,它基于跳表(Skip List)数据结构实现了 ConcurrentNavigableMap 接口。
常用方法
-  lowerKey(K key): 返回小于给定键的最大键,如果不存在则返回 null。
-  floorKey(K key): 返回小于等于给定键的最大键,如果不存在则返回 null。
-  ceilingKey(K key): 返回大于等于给定键的最小键,如果不存在则返回 null。
-  higherKey(K key): 返回大于给定键的最小键,如果不存在则返回 null。
-  subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive): 返回一个包含指定范围的子映射。
-  headMap(K toKey, boolean inclusive): 返回小于等于给定键的部分映射。
-  tailMap(K fromKey, boolean inclusive): 返回大于等于给定键的部分映射。
-  descendingMap(): 返回一个逆序的视图,按键的降序排列。
以上这些方法提供了对映射表进行范围查找和操作的能力。
ConcurrentSkipListMap
ConcurrentSkipListMap 是 Java 中的一个线程安全集合类,实现了ConcurrentMap 接口。它支持高效的插入、删除和查找操作,并提供了强一致性、线程安全的操作保证。
ConcurrentSkipListMap 底层基于跳表,每个节点包含一个键值对和多个指向下一个节点的指针。
在插入、删除、查找元素时,ConcurrentSkipListMap 会从节点的最高层级开始查找,并逐层降低层级,直到找到对应的节点或无法继续降低层级。可以在高并发环境下提供高效的查找、插入、删除操作,并且保证线程安全或强一致性。
ConcurrentSkipListMap 要求键必须实现 Comparable 接口或提供自定义的 Comparator 比较器,以便进行按键排序。
在使用 ConcurrentSkipListMap 时,需要注意元素的相等、哈希等条件,以确保操作的正确性。
特点
ConcurrentSkipListMap 的特性如下:
-  线程安全:ConcurrentSkipListMap 支持多线程的并发访问,保证了线程安全性。 
-  有序键值对映射:ConcurrentSkipListMap 继承了 SortedMap接口,保证了有序的键值对映射集合。
-  可能存在重复的键:ConcurrentSkipListMap 可以存在相同的键,因此在插入键值对时需要注意。 
-  高效的插入、删除和查找操作:ConcurrentSkipListMap 采用跳表的数据结构,在高度平衡与高效性之间取得了一个良好的平衡,具有较高的速度。 
构造方法
- 创建一个空的 ConcurrentSkipListMap,使用键的自然顺序进行排序。
ConcurrentSkipListMap()
- 创建一个空的 ConcurrentSkipListMap,使用指定的比较器对键进行排序。
ConcurrentSkipListMap(Comparator<? super K> comparator)
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>(Comparator.comparingInt(String::length));
- 创建一个包含指定映射中所有映射关系的 ConcurrentSkipListMap
ConcurrentSkipListMap(Map<? extends K, ? extends V> m)
- 创建一个与指定排序映射有相同映射关系的 ConcurrentSkipListMap。
ConcurrentSkipListMap(SortedMap<K, ? extends V> m)
常用方法
-  put(K key, V value):将指定的键值对添加到映射中,如果键已经存在,则将其对应的值替换为新值。
-  remove(Object key):从映射中移除指定键的键值对。
-  get(Object key):获取给定键所对应的值,如果键不存在则返回null。
-  containsKey(Object key):判断映射中是否包含指定的键,返回布尔值。
-  isEmpty():判断映射是否为空,如果为空则返回true,否则返回false。
-  size():返回映射中键值对的数量。
-  keySet():返回一个包含映射中所有键的 Set 集合。
-  values():返回一个包含映射中所有值的 Collection 集合。
-  entrySet():返回一个包含映射中所有键值对的 Set 集合。
-  firstKey():返回映射中的第一个键。
-  lastKey():返回映射中的最后一个键。
-  subMap(K fromKey, K toKey):返回一个子映射,包含所有在给定范围内的键值对。
-  headMap(K toKey):返回一个子映射,包含所有小于给定键的键值对。
-  tailMap(K fromKey):返回一个子映射,包含所有大于等于给定键的键值对。
-  clear():清空映射,移除所有的键值对。
ConcurrentSkipListMap 使用示例
下面是使用 ConcurrentSkipListMap 的代码示例
import java.util.concurrent.ConcurrentSkipListMap;
public class ConcurrentSkipListMapExample {
    public static void main(String[] args) {
        // 创建一个 ConcurrentSkipListMap 实例
        ConcurrentSkipListMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();
        // 插入键值对
        skipListMap.put(3, "Three");
        skipListMap.put(1, "One");
        skipListMap.put(4, "Four");
        skipListMap.put(2, "Two");
        // 输出键值对
        System.out.println("Initial Map: " + skipListMap);
        // 获取键值对
        String value = skipListMap.get(3);
        System.out.println("Value of '3': " + value);
        // 判断是否存在键
        boolean contains = skipListMap.containsKey(5);
        System.out.println("Contains '5': " + contains);
        // 使用 putIfAbsent
        String newValue = skipListMap.putIfAbsent(5, "Five");
        System.out.println("Put or existing value of '5': " + newValue);
        // 使用 computeIfAbsent
        String computedValue = skipListMap.computeIfAbsent(6, k -> "Six");
        System.out.println("Computed value of '6': " + computedValue);
        // 使用 replace
        boolean replaced = skipListMap.replace(5, "Five", "New Five");
        System.out.println("Replaced '5' with 'New Five': " + replaced);
        // 遍历所有键值对
        skipListMap.forEach((key, val) -> System.out.println("Key: " + key + ", Value: " + val));
        // 使用 headMap 和 tailMap
        System.out.println("Head Map (up to 3): " + skipListMap.headMap(3));
        System.out.println("Tail Map (from 3): " + skipListMap.tailMap(3));
        // 使用 subMap
        System.out.println("Sub Map (from 2 to 4): " + skipListMap.subMap(2, 4));
        // 清空映射
        skipListMap.clear();
    }
}


















