我准备了一份10万字的java全面知识总结
领取:
https://pan.quark.cn/s/4e6e3d03407a
线程池使用队列缓存待执行的任务。当核心线程都在忙碌时,新任务就进入队列等待。队列选择直接影响线程池的执行策略和性能表现。
ArrayBlockingQueue基于数组实现,内部使用ReentrantLock保证线程安全。队列维护两个指针:takeIndex指向队头,putIndex指向队尾。
// 核心数据结构
final Object[] items;
int takeIndex; // 取元素的位置
int putIndex; // 放元素的位置
int count; // 当前元素数量
final ReentrantLock lock;
当队列满时,生产者线程会阻塞在notFull条件上。当队列空时,消费者线程会阻塞在notEmpty条件上。
固定大小的任务缓冲池。适合任务量可控的场景。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100) // 最多缓存100个任务
);
在Web应用中处理HTTP请求时使用。能有效控制内存占用,防止任务堆积过多导致内存溢出。
LinkedBlockingQueue基于链表实现,可以指定容量,默认为Integer.MAX_VALUE。使用两把锁分别控制入队和出队操作,提高并发性能。
// 核心数据结构
static class Node<E> {
E item;
Node<E> next;
}
private final ReentrantLock takeLock = new ReentrantLock();
private final ReentrantLock putLock = new ReentrantLock();
入队操作只需获取putLock,出队操作只需获取takeLock。这种设计让生产和消费可以并行进行。
处理突发流量的缓冲队列。Executors.newFixedThreadPool()默认使用此队列。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 5, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>() // 无界队列
);
适合任务处理速度稳定,但任务到达不均匀的场景。比如日志处理、消息处理等。
需要注意队列可能无限增长,要做好监控。
SynchronousQueue不存储元素,每个put操作必须等待对应的take操作。内部使用TransferQueue或TransferStack实现。
公平模式使用队列结构:
// 简化的工作原理
boolean transfer(E e, boolean timed, long nanos) {
QNode s = null;
boolean isData = (e != null);
for (;;) {
QNode t = tail;
QNode h = head;
if (t != null && (t == h || t.isData == isData)) {
// 队列为空或模式相同,尝试添加节点
QNode tn = t.next;
if (t != tail) continue;
if (tn != null) {
advanceTail(t, tn);
continue;
}
if (timed && nanos <= 0) return null;
if (s == null) s = new QNode(e, isData);
if (!t.casNext(null, s)) continue;
advanceTail(t, s);
Object x = awaitFulfill(s, e, timed, nanos);
// ...
}
}
}
适合任务处理速度快,不希望任务排队的场景。Executors.newCachedThreadPool()使用此队列。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<>()
);
典型应用是处理轻量级任务,比如简单的计算任务、快速的IO操作。
PriorityBlockingQueue基于堆实现,支持自定义比较器。内部使用数组存储元素,通过上浮下沉操作维护堆性质。
// 核心数据结构
private transient Object[] queue;
private transient int size;
private transient Comparator<? super E> comparator;
private final ReentrantLock lock;
// 上浮操作
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
需要按优先级处理任务的场景。比如任务调度系统、告警处理系统。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS,
new PriorityBlockingQueue<>()
);
// 任务需要实现Comparable或提供Comparator
class PriorityTask implements Runnable, Comparable<PriorityTask> {
private int priority;
@Override
public int compareTo(PriorityTask other) {
return Integer.compare(this.priority, other.priority);
}
}
DelayQueue基于PriorityQueue实现,只有延时时间到达的元素才能被取出。元素必须实现Delayed接口。
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek();
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return q.poll();
first = null;
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && q.peek() != null)
available.signal();
lock.unlock();
}
}
定时任务执行、缓存过期清理、连接池回收等需要延迟处理的场景。
class DelayedTask implements Runnable, Delayed {
private long executeTime;
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(executeTime - System.nanoTime(), NANOSECONDS);
}
@Override
public int compareTo(Delayed other) {
return Long.compare(this.executeTime, ((DelayedTask) other).executeTime);
}
}
优先选择SynchronousQueue,避免任务堆积,快速响应。
选择ArrayBlockingQueue,固定容量便于容量规划和监控。
选择LinkedBlockingQueue,但要设置合理容量上限。
选择PriorityBlockingQueue,但注意排序开销。
选择DelayQueue,实现精确的延时控制。
监控队列大小变化,及时发现性能瓶颈。设置合理的拒绝策略,避免任务丢失。根据业务特点选择合适的队列类型,不要盲目使用默认配置。
队列选择直接影响线程池的行为特征。理解每种队列的实现原理和适用场景,才能构建高效稳定的并发处理系统。