面试题答案
一键面试高并发下多个线程对Stream执行distinct操作的问题
- 数据一致性问题:多个线程同时操作Stream进行distinct,可能导致部分重复元素没有被正确去除,因为不同线程可能同时处理相同元素,且在哈希表判断重复的过程中出现竞争条件。
- 性能问题:每个线程都尝试更新哈希表以记录已处理元素,频繁的竞争会导致锁争用,大大降低系统性能。
解决方法
- 使用线程安全的哈希表:例如
ConcurrentHashMap
。在distinct
操作时,使用ConcurrentHashMap
来记录已经出现过的元素。由于ConcurrentHashMap
内部采用分段锁机制,允许多个线程同时对不同段进行操作,减少锁争用,提高并发性能。 - 流并行处理时设置合适的并行度:根据系统资源和数据量合理设置并行度。如果并行度设置过高,反而会增加线程切换和资源竞争的开销。可以通过
Stream.parallel().parallelism(degree)
方法设置并行度degree
。 - 外部同步机制:使用
synchronized
关键字或者ReentrantLock
对涉及哈希表操作的代码块进行同步。但这种方式会导致所有线程竞争同一把锁,性能较低,适用于数据量较小,并发度不高的场景。
distinct方法哈希表去重原理
- 基本原理:
distinct
方法在底层实现中,会使用一个哈希表(通常是HashMap
)来记录已经处理过的元素。对于流中的每个元素,会计算其哈希值,通过哈希值快速定位到哈希表中的位置。 - 具体步骤:
- 计算元素的哈希值:调用元素的
hashCode()
方法获取哈希值。这个哈希值会被用来确定元素在哈希表中的大致存储位置。 - 检查哈希冲突:如果不同元素的哈希值相同(哈希冲突),会进一步调用
equals
方法来判断两个元素是否真的相等。如果equals
方法返回true
,则认为这两个元素是重复的。 - 存储元素:如果元素不重复,则将其存储到哈希表中。在
HashMap
中,元素会被存储在对应的哈希桶(链表或红黑树,取决于哈希表的状态)中。后续再有元素进入时,重复上述过程进行去重判断。
- 计算元素的哈希值:调用元素的