MST
星途 面试题库

面试题:Java ArrayBlockingQueue公平性实现原理剖析

深入分析Java ArrayBlockingQueue中公平性模式的具体实现机制。从底层数据结构、锁的实现以及线程调度等方面,说明公平性模式是如何确保等待时间最长的线程优先获取资源的。同时,对比非公平性模式在这些方面的差异。
50.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. ArrayBlockingQueue 公平性模式实现机制

底层数据结构

  • ArrayBlockingQueue 基于数组实现,用于存储元素。数组的容量在创建队列时就已确定,无法动态扩展。
  • 它有两个指针 takeIndexputIndex 分别指向队头和队尾元素的位置,通过这两个指针来控制数据的入队和出队操作。

锁的实现

  • 使用 ReentrantLock 作为锁机制,在公平性模式下创建 ReentrantLock 时传入 true,即 new ReentrantLock(true)
  • ReentrantLock 内部维护了一个 Sync 抽象类,公平模式下使用 FairSync 实现类。FairSync 在尝试获取锁时,会先检查同步队列中是否有等待时间更长的线程。如果有,则当前线程会进入同步队列等待,而不是直接尝试获取锁。

线程调度

  • 等待线程被存储在 ReentrantLock 的同步队列(AbstractQueuedSynchronizerCLH 队列)中。
  • 当锁可用时,ReentrantLock 会按照线程在同步队列中的顺序,唤醒等待时间最长的线程。这个线程获取锁后,会从队列中移除,然后执行相应的入队或出队操作。

2. 公平性模式与非公平性模式的差异

底层数据结构

  • 公平性和非公平性模式在底层数据结构上没有差异,都是基于数组和指针 takeIndexputIndex 来实现队列操作。

锁的实现

  • 公平性模式ReentrantLock 使用 FairSync,获取锁时会先检查同步队列中是否有等待线程,若有则排队等待,按顺序获取锁。
  • 非公平性模式ReentrantLock 使用 NonfairSync,获取锁时不会检查同步队列,直接尝试获取锁,即使队列中有等待线程,当前线程也可能优先获取锁。这种方式在高并发场景下可能导致某些线程长时间等待。

线程调度

  • 公平性模式:线程严格按照在同步队列中的等待顺序获取锁,保证等待时间最长的线程优先获取资源。
  • 非公平性模式:线程获取锁的顺序不确定,可能导致部分线程频繁获取锁,而其他线程等待时间过长,即所谓的 “饥饿” 现象。但在高并发下,非公平性模式因为减少了线程切换的开销,通常具有更高的吞吐量。