手写线程池与锁

共 19 题
#

1. 手写线程池,任务队列、Worker 循环、拒绝策略、优雅关闭如何实现?

A shutdown 会中断所有正在执行的任务
B 拒绝策略只在队列满时触发,与线程数无关
C shutdownNow 会等待任务自然完成
D shutdown 不再接受新任务,但等待已提交任务完成 ✓ 正确答案
#

2. 手写一个可重入锁(基于 synchronized 或 AQS 思路)并说明重入计数的作用?

A 重入计数用于让锁在嵌套时也能被正确释放 ✓ 正确答案
B 重入计数越大锁越安全
C 可重入锁不允许同一线程重复加锁
D 释放时无需检查持有者
#

3. ThreadLocal 的实现原理,ThreadLocalMap 的线性探测与弱引用 Entry 如何导致内存泄漏,如何正确清理?

A 弱引用 key 回收后 value 仍可能残留,造成泄漏 ✓ 正确答案
B Entry 的 key 是强引用,ThreadLocal 不会回收
C 用完 remove 反而增加泄漏风险
D 线程池中线程复用不会泄漏
#

4. 手写 CountDownLatch 与 CyclicBarrier,基于 AQS 共享锁与栅栏重置(Generation)的核心差异如何?

A CyclicBarrier 通过 Generation 实现可重置 ✓ 正确答案
B CountDownLatch 可以重复使用
C CyclicBarrier 是一次性的
D CountDownLatch 基于 ReentrantLock + Condition
#

5. 手写 AQS 简化版,CLH 等待队列、独占/共享模式的 acquire/release

A acquire 失败时线程直接返回
B 共享模式不需要唤醒后继
C release 通过唤醒后继节点让等待线程继续 ✓ 正确答案
D CLH 队列用数组存储等待线程
#

6. 手写读写锁,读者优先与写者优先策略的实现差异如何?

A 新读者到来时若已有写者等待,读者也等待 ✓ 正确答案
B 写者优先会导致读者饥饿
C 读者优先会饿死读者
D 读写锁允许多个写者并发
#

7. 手写一个限流器(令牌桶/滑动窗口)并对比两种算法的内存与精度?

A 令牌桶无法控制平均速率
B 滑动窗口内存比令牌桶更小
C 令牌桶精度比滑动窗口更高
D 令牌桶支持一定突发流量 ✓ 正确答案
#

8. 手写 Semaphore,AQS 共享计数的 acquire/release 与公平/非公平模式的实现差异如何?

A 非公平模式会检查队列中是否有等待者
B 公平模式吞吐总比非公平高
C 公平模式允许新线程插队
D 公平模式保证先到先得,避免饥饿 ✓ 正确答案
#

9. 手写工作窃取(Work-Stealing)线程池或 ForkJoinPool 的分治模型,窃取为什么从队尾?

A 窃取者从队头取任务以获得最新任务
B 工作窃取必须用全局锁保护
C 窃取从队尾会使任务重复执行
D 窃取从队尾减少与拥有者的竞争,且偏向取大任务 ✓ 正确答案
#

10. 手写支持超时与中断的锁,LockSupport.parkNanos 与 wait/notify 相比的可靠性差异如何?

A unpark 提前于 park 执行时信号会丢失
B LockSupport 不受锁约束,且 unpark 有许可计数不会丢信号 ✓ 正确答案
C wait 不需要在循环中检查条件
D parkNanos 不支持响应中断
#

11. 手写线程池时如何埋点监控(任务数、队列深度、拒绝数)与告警

A 队列深度反映积压情况,可预警线程池耗尽 ✓ 正确答案
B 拒绝数不影响资源耗尽判断
C 指标计数必须用全局锁
D 活跃线程数一定等于 maxPoolSize
#

12. 手写线程池时如何支持"核心线程超时回收"(allowCoreThreadTimeOut)与动态调整 corePoolSize,空闲线程的 keepAlive 如何实现?

A 核心线程永远不会空闲回收
B keepAlive 用 take() 实现
C allowCoreThreadTimeOut 让核心线程空闲后也能被回收 ✓ 正确答案
D 调整 corePoolSize 不影响已在线程
#

13. 手写一个异步任务编排器(依赖 DAG),任务间的依赖、失败传播与超时如何实现,与 CompletableFuture 的 thenCombine/allOf 对应关系如何?

A 失败只影响自身不影响后继
B 任务前置全部完成后才就绪执行 ✓ 正确答案
C thenCombine 与 allOf 表示"任一个完成"即可
D 超时任务无需处理
#

14. 手写线程池的拒绝策略扩展,如何实现"重试入队""降级到其他池""优雅降级"三种自定义策略,各自适用什么场景?

A 重试入队适合愿意等待并避免丢任务的场景 ✓ 正确答案
B 降级到其他池会丢弃任务
C 优雅降级就是抛异常
D 拒绝策略只能用于默认线程池
#

15. 手写"生产者-消费者",如何避免忙等与信号丢失?

A 信号丢失不影响正确性
B 忙等比阻塞等待更省 CPU
C 条件等待需要在循环中检查条件,避免信号丢失 ✓ 正确答案
D 生产者-消费者必须使用自旋
#

16. 手写 FutureTask 简化版,状态机(NEW/RUNNING/DONE/CANCELLED)与等待唤醒如何实现?

A 状态不需要 volatile
B 取消后仍可执行任务
C 状态为 DONE 时 get 才能返回 ✓ 正确答案
D RUNNING 状态可被多次执行
#

17. 手写读写锁的升级/降级边界,为什么读锁不能升级为写锁,写锁降级为何安全?

A ReentrantReadWriteLock 支持读锁升级
B 写锁降级为读锁可能死锁
C 读锁升级写锁是安全的
D 读锁升级为写锁可能造成死锁 ✓ 正确答案
#

18. 手写 Ticket Lock(公平自旋锁)与自旋锁在临界区极短场景的应用

A 自旋锁在临界区极长时也高效
B Ticket Lock 是公平的,先取号先获得 ✓ 正确答案
C 自旋锁在单核下表现最好
D 自旋锁会阻塞线程
#

19. 手写"带超时的阻塞队列",offer(timeout) 与 poll(timeout) 的底层条件等待如何实现,与 ThreadPoolExecutor 的 workQueue 如何配合?

A 非核心线程用 workQueue.poll(keepAliveTime) 实现空闲回收 ✓ 正确答案
B 核心线程用 poll 而非 take
C awaitNanos 无需循环重算剩余时间
D 超时队列不能用于线程池