Java 8 JUC 知识点汇总
去年 11 月的时候莫名其妙接到了申通快递的面试,想起来我 4 个月前投递过,看来是捞起来被 KPI 面了。 已经是 2026 年了,Java 25 都作为 LTS 了,虚拟线程都把业务开发中的锁设计和同异步性能差异干碎了。 还在问 AQS,还在问 AQS 三剑客,最后由于不熟悉 CountDownLatch 的写法而被评价为不匹配,心累。
毁灭吧,Java。
JUC 主要知识点如下:
-
线程池 ThreadPoolExexector & 阻塞队列 BlockingQueue & 异步调度 CompletableFuture
-
并发容器 ConcurrentHashMap / CopyOnWriteArrayList
-
同步工具类
- 原子类 AtomicInteger
- AQS 三剑客 CountDownLatch / CyclicBarrier / Semaphore
- 高性能计数器 LongAdder
-
显式锁
- 可重入锁 ReentrantLock & ReentrantReadWriteLock
- 时间戳乐观锁 StampedLock
ThreadPoolExecutor
ThreadPoolExecutor + CompletableFuture 是 Java 8 并发编程的基石
线程池八大参数
- CorePoolSize 核心线程数
- MaxPoolSize 最大线程容量
- KeepAliveTime 线程等待时间
- TimeUnit 等待时间的单位
- BlockingQueue<Runnable> 工作队列
- RejectedExecutionHandler 拒绝策略
- ThreadFactory 线程工厂
线程池的调度顺序
- 查看核心线程是否可用
- 如不可用,则加入队列
- 如队列满,则检查最大线程容量,尝试创建非核心线程
- 如无法创建非核心线程,则执行拒绝策略
我个人常年使用线程池一直处于误区:
我认为核心线程满的时候会直接创建非核心线程,无法创建非核心线程才会加入工作队列,这是错误的。
仔细揣摩这样的策略,会发现这使得 CorePoolSize 这个参数的设计比较尴尬。
线程池的设计初衷,是池化设计 + 预加载的结合,用运行时廉价的队列缓冲代替昂贵的线程创建
常用的阻塞队列
ArrayBlockingQueue 数组阻塞队列
- 强制有界
LinkedBlockingQueue 链表阻塞队列
- 默认无界(可能导致 OOM),因此通常在初始化时传入容量
- Executors.newFixedThreadPool() 使用该队列
SynchronousQueue 同步移交队列
- 没有容量
- Executors.newCachedThreadPool() 使用该队列
PriorityBlockingQueue 优先阻塞队列
- 可排序的优先队列
DeleyedWorkQueue 延迟队列
- ScheduledThreadPoolExecutor 专用,按延迟时间排列
- 小顶堆实现
为什么使用阻塞队列而不是普通队列?
阻塞队列特地放在 JUC 包下,说明他是线程安全的。
阻塞二字,指的是阻塞队列特有的操作可能会阻塞该线程。(阻塞行为实现了同步,同步即串行,也就是线程安全)
普通队列
Queue<String> normalQueue = new LinkedList<>();
// 基本操作
normalQueue.offer("task"); // 入队,失败返回false
normalQueue.poll(); // 出队,队列空返回null
normalQueue.peek(); // 查看,队列空返回null
阻塞队列
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
// 阻塞操作
blockingQueue.put("task"); // 入队,队列满时阻塞等待
blockingQueue.take(); // 出队,队列空时阻塞等待
阻塞队列的核心设计
等待 / 通知机制
// 阻塞队列的简化实现
public class SimpleBlockingQueue<E> {
private final Queue<E> queue = new LinkedList<>();
private final int capacity;
public SimpleBlockingQueue(int capacity) {
this.capacity = capacity;
}
// 阻塞式入队
public synchronized void put(E item) throws InterruptedException {
while (queue.size() == capacity) { // 队列满
wait(); // 释放锁,等待
}
queue.offer(item);
notifyAll(); // 通知消费者
}
// 阻塞式出队
public synchronized E take() throws InterruptedException {
while (queue.isEmpty()) { // 队列空
wait(); // 释放锁,等待
}
E item = queue.poll();
notifyAll(); // 通知生产者
return item;
}
}
Java 8 实际底层设计:可重入锁 + Condition