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 包下,说明他是线程安全的。
阻塞二字,指的是阻塞队列特有的操作可能会阻塞该线程。(阻塞行为实现了同步,同步即串行,也就是线程安全)
普通队列
1Queue<String> normalQueue = new LinkedList<>();
2// 基本操作
3normalQueue.offer("task"); // 入队,失败返回false
4normalQueue.poll(); // 出队,队列空返回null
5normalQueue.peek(); // 查看,队列空返回null
阻塞队列
1BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
2// 阻塞操作
3blockingQueue.put("task"); // 入队,队列满时阻塞等待
4blockingQueue.take(); // 出队,队列空时阻塞等待
阻塞队列的核心设计
等待 / 通知机制
1// 阻塞队列的简化实现
2public class SimpleBlockingQueue<E> {
3 private final Queue<E> queue = new LinkedList<>();
4 private final int capacity;
5
6 public SimpleBlockingQueue(int capacity) {
7 this.capacity = capacity;
8 }
9
10 // 阻塞式入队
11 public synchronized void put(E item) throws InterruptedException {
12 while (queue.size() == capacity) { // 队列满
13 wait(); // 释放锁,等待
14 }
15 queue.offer(item);
16 notifyAll(); // 通知消费者
17 }
18
19 // 阻塞式出队
20 public synchronized E take() throws InterruptedException {
21 while (queue.isEmpty()) { // 队列空
22 wait(); // 释放锁,等待
23 }
24 E item = queue.poll();
25 notifyAll(); // 通知生产者
26 return item;
27 }
28}
Java 8 实际底层设计:可重入锁 + Condition