面试题答案
一键面试可能出现的性能瓶颈
- 队列满时阻塞:
ArrayBlockingQueue
容量固定,当队列满时,新任务加入会阻塞,导致生产任务线程等待,影响整体吞吐量。 - 锁竞争:由于其内部使用一把锁来控制入队和出队操作,在高并发场景下,大量线程同时进行入队或出队操作,会产生激烈的锁竞争,降低并发性能。
代码优化提升性能
- 存取策略优化:
- 增加队列容量:适当增加
ArrayBlockingQueue
的初始容量,减少队列满的频率,从而降低任务阻塞等待的时间。例如:
- 增加队列容量:适当增加
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
- **使用有界队列的替代方案**:如 `LinkedTransferQueue`,它是一个无界队列,在高并发场景下性能更好。`LinkedTransferQueue` 允许生产者线程在队列满时,直接将任务传递给正在等待的消费者线程,而无需等待队列有空闲空间。示例代码如下:
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;
public class LinkedTransferQueueExample {
public static void main(String[] args) {
TransferQueue<Integer> queue = new LinkedTransferQueue<>();
Thread producer = new Thread(() -> {
try {
queue.transfer(1);
System.out.println("Produced 1");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
Integer value = queue.take();
System.out.println("Consumed " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
consumer.start();
producer.start();
}
}
- 锁机制优化:
- 使用分段锁:如果自行实现队列,可以借鉴分段锁的思想,将队列分为多个段,每个段使用不同的锁来控制入队和出队操作,减少锁竞争。例如,假设有一个自定义的分段队列:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SegmentQueue {
private final int segmentCount;
private final Lock[] locks;
private final Object[][] segments;
private final int segmentSize;
public SegmentQueue(int segmentCount, int segmentSize) {
this.segmentCount = segmentCount;
this.segmentSize = segmentSize;
locks = new Lock[segmentCount];
segments = new Object[segmentCount][segmentSize];
for (int i = 0; i < segmentCount; i++) {
locks[i] = new ReentrantLock();
}
}
public void enqueue(Object item, int segmentIndex) {
locks[segmentIndex].lock();
try {
// 找到合适的位置插入item
for (int i = 0; i < segmentSize; i++) {
if (segments[segmentIndex][i] == null) {
segments[segmentIndex][i] = item;
return;
}
}
} finally {
locks[segmentIndex].unlock();
}
}
public Object dequeue(int segmentIndex) {
locks[segmentIndex].lock();
try {
for (int i = 0; i < segmentSize; i++) {
if (segments[segmentIndex][i] != null) {
Object item = segments[segmentIndex][i];
segments[segmentIndex][i] = null;
return item;
}
}
return null;
} finally {
locks[segmentIndex].unlock();
}
}
}
这里简单实现了一个分段队列,通过不同的锁来控制不同段的操作,减少了锁竞争。实际应用中,还需要考虑更多边界情况和优化。
- 采用非阻塞队列:
ConcurrentLinkedQueue
是一个基于链表的无界线程安全队列,采用无锁算法实现入队和出队操作,能在高并发场景下提供较好的性能。示例代码:
import java.util.concurrent.ConcurrentLinkedQueue;
public class ConcurrentLinkedQueueExample {
public static void main(String[] args) {
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
Thread producer = new Thread(() -> {
queue.add(1);
System.out.println("Produced 1");
});
Thread consumer = new Thread(() -> {
Integer value = queue.poll();
if (value != null) {
System.out.println("Consumed " + value);
}
});
consumer.start();
producer.start();
}
}
通过上述优化,可以在一定程度上提升在高并发场景下任务队列的性能。