# 1. Wait-Free 与 Lock-Free 的区别中为什么真正的 Wait-Free 实现极其困难?实际工程中的取舍? A Wait-Free 实现简单,性能开销小 B Lock-Free 保证每个线程不被饿死 C Wait-Free 保证每个线程在有限步数内完成,Lock-Free 只保证系统整体前进 ✓ 正确答案 D 两者都允许单个线程无限等待
# 2. 读-写锁与写优先中在缓存一致性场景如何选择? A 读-写锁不允许读者并发读 B 读优先策略会让写者获得更高吞吐 C 缓存一致性场景不应考虑写者公平性 D 写优先策略保证写者不饥饿,避免长期被读者阻塞 ✓ 正确答案
# 3. 环形缓冲(ring buffer)的写满/读空判定(size 计数法) A size 计数法无法区分 head==tail 时空与满的歧义 B size 计数法用独立计数器区分空与满,能存满整个容量 ✓ 正确答案 C size 计数法必须浪费一格空间 D size 计数法只适用于多生产者场景
# 4. RCU 与读写锁、无锁链表/队列的边界差异? A RCU 读者必须加锁才能保证安全 B RCU 读者无锁且可并发读旧数据,写者延迟回收旧版本 ✓ 正确答案 C 读写锁读者无锁,性能最高 D 无锁结构与 RCU 一样需要 grace period 延迟回收
# 5. Seqlock(序列锁)的原理中适合读多写少的场景?写者饥饿问题如何缓解? A 读者通过两次读序列号并比较来校验数据一致性,无需加锁 ✓ 正确答案 B Seqlock 适合写多读少的场景 C 读者需要加写锁才能获得一致性 D Seqlock 的读者会阻塞写者
# 6. MPMC(多生产者多消费者)队列的设计中 LMAX Disruptor 的 Ring Buffer 为什么比 LinkedBlockingQueue 快? A 它比 LinkedBlockingQueue 慢,只是更简单 B 它仍使用一把全局锁保护所有操作 C 它依赖动态分配节点来降低成本 D 它预分配环形缓冲、用无锁序号推进并规避伪共享 ✓ 正确答案
# 7. 读多写少场景的 COW 与 seqlock 选择中为什么 COW 适合不可变引用(atomic shared_ptr),而 seqlock 适合标量读? A COW 适合标量频繁读,seqlock 适合大对象引用 B COW 用原子指针发布不可变快照,适合读者拿引用的场景;seqlock 用序列号校验,适合标量读 ✓ 正确答案 C COW 读者必须加锁 D seqlock 每次读都要复制整个大对象
# 8. Flat Combining 技术中如何将多线程竞争转化为单线程顺序执行以提升吞吐? A 它让单一执行者在持锁时批量处理提交的操作,减少锁竞争与缓存乒乓 ✓ 正确答案 B 每个线程都直接操作数据结构,并行执行 C 它只适用于无锁实现,不适用于锁 D 它通过增加锁竞争来提升吞吐
# 9. Copy-on-Write 容器的适用边界中读多写少场景的收益与写放大代价? A COW 写操作不复制任何数据 B 它适合写非常频繁的场景,写放大可忽略 C COW 读者必须加锁才能保证一致 D 它适合读多写少、容器适中的场景,读者无锁并获得一致快照,但每次写要全量复制 ✓ 正确答案
# 10. CAS 强竞争下的活锁问题中无锁队列为何可能长时间无法前进,backoff 与批次化如何缓解? A backoff 通过增加 CAS 频率来解决问题 B 活锁会导致线程全部阻塞死亡 C 活锁下线程都在运行但互相 CAS 失败重试,系统无法取得进展 ✓ 正确答案 D 批次化会增加 CAS 次数,加剧竞争
# 11. 为何不能用"头==尾"同时表示空与满,需要额外标记 A 空与满时 head 与 tail 位置重合,需用 size 计数或标志位额外区分 ✓ 正确答案 B 空时 head!=tail,满时 head==tail,可直接区分 C 只要 head 与 tail 是整数就不会歧义 D 头==尾只能表示满,不能表示空
# 12. Linux 内核中 RCU 在路由表/文件系统的典型运用 A RCU 只用于文件系统,不用于路由表 B 内核路由查找必须加锁保护 C 路由表与 dentry 缓存读路径无锁,写者用 RCU 替换并延迟回收旧对象 ✓ 正确答案 D 写者更新后立即回收旧对象
# 13. RCU 与垃圾回收在"延迟释放"理念上的相似 A RCU 依赖可达性分析自动回收 B RCU 立即回收旧对象,GC 才延迟 C GC 用过 grace period 判断安全 D 两者都延迟释放仍被并发引用的对象,待确认无人引用后再回收 ✓ 正确答案
# 14. RCU 在 Linux 内核、读多写少场景的典型应用? A RCU 适合写非常频繁、读者必须读最新的场景 B 内核路由表、dentry 缓存等读多写少结构用 RCU 实现读者无锁 ✓ 正确答案 C RCU 读者需要加锁才能读 D RCU 只适用于用户态,不适用于内核
# 15. RCU 使用有哪些常见误区(写者开销、内存回收时机)? A 写者需等待 grace period 才能回收旧对象,且 `synchronize_rcu` 有真实写延迟开销 ✓ 正确答案 B RCU 读者无锁,因此写路径也完全免费 C 写完发布指针后可以立即 free 旧对象 D 读者可以在临界区内睡眠以加速
# 16. RCU 的核心概念中读侧临界区、宽限期(grace period)与回收? A 宽限期结束后读者仍可能引用旧指针 B 写者发布新指针后需等宽限期结束(所有读者退出临界区)才能回收旧对象 ✓ 正确答案 C 读者在临界区内可以任意阻塞 D 回收与宽限期无关,写者可立即 free
# 17. RCU 适用于"读多写少"且写者能容忍延迟回收的场景 A RCU 读者必须读到最新值 B RCU 适合写非常频繁、读者必须读最新的场景 C RCU 适合读多写少且写者能容忍延迟回收的场景 ✓ 正确答案 D RCU 写者可以立即释放旧对象
# 18. Lock-Free Queue(Michael-Scott)的 CAS 循环设计中 ABA 问题如何用 Hazard Pointer 或 Epoch-Based Reclamation 解决? A Hazard Pointer 无法解决 ABA 问题 B ABA 问题是因为 CAS 没有版本号导致的,与内存回收无关 C EBR 按单个指针粒度保护 D Hazard Pointer 保护被并发引用的指针推迟回收,EBR 按时代批量回收对象 ✓ 正确答案
# 19. RCU(Read-Copy-Update)的核心思想中读路径无锁?Grace Period 如何确定安全回收时机?Linux 内核中的应用? A 回收是即时的,无需等待 B 写者在原地修改共享数据,读者加锁 C 读者必须加锁才能读到一致数据 D 写者复制-修改-发布新指针,读者无锁读,grace period 后回收旧对象 ✓ 正确答案
# 20. Concurrent Skip List 的设计中为什么 Redis 的 ZSET 选择跳表而非红黑树?并发跳表的锁粒度(per-node vs per-level)? A Redis 的 ZSET 选跳表是因为实现简单、支持范围查询且对并发友好,而非红黑树 ✓ 正确答案 B 红黑树的旋转操作对并发更友好 C 并发跳表只能使用 per-level 锁,无法细粒度 D 跳表不支持范围查询
# 21. Treiber 无锁栈与 Michael-Scott 队列的区别中栈的 CAS 循环比队列简单,队列为何需要 dummy 节点? A 队列的 dummy 节点用于存储数据 B 队列只有一个指针,比栈简单 C 栈需要 dummy 节点 D 栈只有一个栈顶指针、CAS 循环简单;队列双指针且需 dummy 节点消除空队列歧义 ✓ 正确答案
# 22. Hazard Pointer 与 Epoch-Based Reclamation(EBR)的对比中各自的内存开销和适用场景? A Hazard Pointer 开销比 EBR 小 B EBR 按单个指针保护,开销最大 C Hazard Pointer 按指针精确保护、延迟低但每线程槽位开销大;EBR 按时代批量回收、开销小但可能延迟回收 ✓ 正确答案 D 两者都立刻释放对象
# 23. Concurrent Hash Map 的设计演进中 Java ConcurrentHashMap(JDK 7 分段锁 → JDK 8 CAS+synchronized)vs C++ TBB vs Rust DashMap? A JDK 8 用桶级别 CAS+synchronized 替代 JDK 7 的分段锁,并发度更高 ✓ 正确答案 B JDK 7 的并发度比 JDK 8 更高 C 所有实现都用单一全局锁 D TBB 的锁粒度比 Java 8 更细
# 24. Disruptor 环形缓冲中单生产者/消费者无锁模型与伪共享(false sharing)规避? A SPSC 下用相邻序号无锁推进,并用缓存行填充隔离各线程热变量避免伪共享 ✓ 正确答案 B SPSC 下仍需 CAS 保证正确 C 伪共享不影响性能,无需规避 D 缓存行填充会提高延迟
# 25. ConcurrentHashMap 在 Java 8 中 CAS+synchronized 的演进中从分段锁到桶级别锁,sizeCtl 控制扩容,红黑树退化优化 A sizeCtl 只记录元素个数 B 它仍使用 JDK 7 的分段锁 C 它用桶级别 CAS+synchronized 替代分段锁,用 sizeCtl 协调扩容,链表超阈值转红黑树 ✓ 正确答案 D 链表长度无论多大都不转红黑树
# 26. MPMC 无锁队列为何需要 CAS 与可能的 ABA 问题 A ABA 问题与内存回收无关 B MPMC 无需 CAS,靠锁即可 C MPMC 需靠 CAS 原子推进共享指针,ABA 问题源于内存被释放重用导致地址回绕,可用版本号或延迟回收解决 ✓ 正确答案 D 单生产者比多生产者更易触发 ABA
# 27. 单生产者单消费者(SPSC)无锁队列如何靠内存屏障实现 A SPSC 队列必须用锁保护 B SPSC 仍需要 CAS 才能保证正确 C 内存屏障只能用于多生产者场景 D SPSC 无竞争,用 release 发布、acquire 读取的屏障保证数据可见性即可,无需锁或 CAS ✓ 正确答案
# 28. 无锁队列在高频交易/日志管道中的真实收益与调试难度 A 无锁队列只能用于低频场景 B 无锁队列比锁更快且更容易调试 C 无锁队列不存在 ABA 问题 D 它提供低延迟、高吞吐、无阻塞,但并发 bug 难复现、内存回收与内存序调试难度大 ✓ 正确答案
# 29. CAS 的 ABA 问题如何用版本号/双字 CAS 解决 A 双字 CAS 无法原子更新两个字段 B 版本号法只能解决死锁,不能解决 ABA C 版本号法或双字 CAS 在比较中加入随修改递增的版本号,使地址回绕不再被误判为匹配 ✓ 正确答案 D ABA 问题无需解决,不影响正确性
# 30. Disruptor 框架如何用无锁 ring + 序号屏障实现高吞吐 A Disruptor 依赖锁来协调生产者与消费者 B 预分配 ring 复用槽位,序号屏障用序号协调生产者与消费者的读写边界,实现无锁高吞吐 ✓ 正确答案 C 序号屏障是用于分配内存的 D Disruptor 不预分配,靠动态分配节点
# 31. 内存序(acquire/release)在无锁结构中的关键作用 A 无锁结构不需要内存序,靠 CAS 即可 B release 发布数据、acquire 读取数据,二者配对形成发布-获取同步,保证数据可见性 ✓ 正确答案 C acquire 只影响写,release 只影响读 D 宽松内存序能保证数据可见性
# 32. 无锁读是否真的更快,内存屏障与缓存一致性的隐性成本 A 无锁读在任何场景都一定更快 B 无锁读省去锁等待,但内存屏障与缓存一致性(MESI 失效)是隐性成本,低竞争/读多写少时更划算 ✓ 正确答案 C 无锁结构没有缓存一致性成本 D 内存屏障是无锁结构的免费功能
# 33. COW(写时复制)页表/数据结构与 RCU 思想的联系 A 两者都通过复制旧数据、修改后原子发布、读者共享一致快照并延迟处理旧版本 ✓ 正确答案 B COW 与 RCU 读者都需要加锁 C COW 写者不复制数据 D RCU 读者读到的版本一定是新的
# 34. RCU(Read-Copy-Update)如何让读者完全无锁 A 写者复制-修改-原子发布新指针,读者只读当前指针并声明临界区,写者延迟回收旧版本 ✓ 正确答案 B 读者需要加锁才能读取数据 C 写者在原地修改数据,读者等待 D 读者必须用 CAS 读取指针
# 35. seqlock 如何用序列号让读者检测写者并发从而避免锁 A 读者必须加锁才能读取一致数据 B 读者读两次序列号(偶数)并比较,检测到写者并发则重试,从而无需加锁 ✓ 正确答案 C 序列号是奇数表示写完成 D 读者检测到写者后会阻塞等待