从我使用的库中得到
ConcurrentMap
。我想获取它的密钥为 Set
。
如何以线程安全的方式做到这一点(因为 Kotlin 集合 API 是线程不安全的)?
根据docs实现`ConcurrentMap的实现时预期的保证:
提供线程安全和原子性保证的Map。
为了维持指定的保证,默认实现 包括从 Map 继承的 putIfAbsent(K, V) 的方法必须是 被该接口的实现覆盖。相似地, Map.keySet() 方法返回的集合的实现, Map.values() 和 Map.entrySet() 必须重写方法,例如 必要时删除If以保持原子性保证。
内存一致性影响:与其他并发集合一样, 将对象放入 ConcurrentMap 之前在线程中执行的操作如下 键或值发生在访问之后的操作或 从另一个线程的 ConcurrentMap 中删除该对象。
该接口是 Java Collections Framework 的成员。
实现是
ConcurrentHashMap
:
支持完全并发检索和高预期更新并发的哈希表。该类遵循与 Hashtable 相同的功能规范,并包含与 Hashtable 的每个方法相对应的方法版本。然而,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。在依赖其线程安全性但不依赖其同步细节的程序中,此类与 Hashtable 完全可互操作。
ConcurrentHashMap 支持一组顺序和并行批量操作,与大多数 Stream 方法不同,这些操作被设计为安全且通常明智地应用,即使映射由其他线程同时更新;例如,在计算共享注册表中值的快照摘要时。共有三种操作,每种操作有四种形式,接受带有键、值、条目和(键,值)对作为参数和/或返回值的函数。由于 ConcurrentHashMap 的元素不以任何特定方式排序,并且可能在不同的并行执行中以不同的顺序进行处理,因此所提供函数的正确性不应依赖于任何顺序,也不应依赖于任何其他可能暂时更改的对象或值。计算正在进行中;除了 forEach 操作之外,理想情况下应该是无副作用的。 Map.Entry 对象上的批量操作不支持 setValue 方法。
另一个实现是ConcurrentSkipListMap:
此类实现了 SkipLists 的并发变体,为 containsKey、get、put 和 remove 操作及其变体提供预期的平均 log(n) 时间成本。插入、删除、更新和访问操作由多个线程安全地并发执行。
我建议您应该使用其中一种(或两种)实现来尝试您担心的场景,看看它们是否满足您的期望,如果是,那么您就完成了。如果没有,则检测哪些方法的行为不符合您的预期,并创建一个子类来修复问题并使用它。