为什么多线程是技术面试的“必考题”?
在多线程面试入门教程中,我们发现:超过87%的中高级Java/C++岗位在技术面试中会涉及并发编程问题。从基础的线程创建到复杂的线程池设计,从synchronized原理到死锁检测与预防,这些知识点不仅是系统设计能力的体现,更是系统稳定性与性能的保障。
本教程专为准备多线程面试的开发者设计,结合真实企业面试题(如阿里、腾讯、字节跳动等),系统梳理核心考点,并提供可运行的代码示例、常见陷阱解析与性能优化建议。无论你是应届生还是3年经验工程师,都能从中获得清晰的学习路径与实用技巧。
立即进入学习路径 →① 线程基础:从创建到生命周期
线程的三种创建方式(Java)
在多线程面试入门教程中,线程创建是最基础但极易被误答的知识点。开发者常混淆“继承Thread类”与“实现Runnable接口”的区别,更忽略线程池作为首选方案的工程实践意义。
// 方式1:继承Thread类(不推荐)
class MyThread extends Thread {
public void run() {
System.out.println("继承Thread线程执行中...");
}
}
// 方式2:实现Runnable接口(推荐)
class MyRunnable implements Runnable {
public void run() {
System.out.println("实现Runnable线程执行中...");
}
}
Thread t2 = new Thread(new MyRunnable());
// 方式3:使用Lambda表达式(最简洁)
Thread t3 = new Thread(() -> {
System.out.println("Lambda线程执行中...");
});
线程的五大状态与生命周期
Java线程状态包括:NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(计时等待)、TERMINATED(终止)。面试中常考:
• sleep()与wait()的区别:sleep不释放锁,wait释放对象锁
• yield()的作用:提示调度器重新选择线程,但不保证立即生效
• join()原理:通过wait()实现等待目标线程终止
当线程A调用threadB.join()时,A进入WAITING状态,等待threadB的notifyAll()触发。源码中通过synchronized(this) + this.wait()实现。
线程安全的三大核心问题
在多线程面试入门教程中,线程安全问题被反复强调。三大核心问题为:
① 可见性:一个线程修改的共享变量,其他线程能否立即看到
② 原子性:操作是否会被其他线程中断
③ 有序性:指令是否按预期顺序执行(受重排序影响)
这些问题的根源在于JVM内存模型(JMM)中主内存与工作内存的分离。
class UnsafeDemo {
private static boolean flag = true;
public static void main(String[] args) {
new Thread(() -> {
while (flag) {
// 循环体
}
}).start();
// 1秒后修改flag
try { Thread.sleep(1000); } catch (Exception e) {}
flag = false; // 线程可能永远看不到更新!
}
}
volatile关键字深度解析
在多线程面试入门教程中,volatile常被误解为“轻量级synchronized”。实际上:
• 保证可见性与有序性,但不保证原子性
• 禁止指令重排序(通过内存屏障实现)
• 常用于状态标记、双重检查锁中的单例模式
② 同步机制:锁、条件与并发工具类
synchronized的四种使用场景
在多线程面试入门教程中,synchronized是Java并发的基石。其四种用法为:
① 修饰实例方法(锁当前对象实例)
② 修饰静态方法(锁当前类的Class对象)
③ 修饰代码块(锁指定对象)
④ 修饰类的Class对象(锁整个类)
// 错误示例:多个实例共享同一把锁?不!
class Counter {
private int count = 0;
public synchronized void increment() { count++; } // 锁的是this实例
}
Counter c1 = new Counter();
Counter c2 = new Counter();
// c1和c2的线程互不影响 → count可能不准确!
ReentrantLock与synchronized对比
在多线程面试入门教程中,ReentrantLock提供更多高级特性:
• 支持公平锁(Fair Lock)
• 支持可中断锁获取(lockInterruptibly)
• 支持尝试获取锁(tryLock)
• 支持多个条件队列(Condition)
并发工具类实战:CountDownLatch、CyclicBarrier、Semaphore
在多线程面试入门教程中,这些工具类常被用于高并发场景:
• CountDownLatch:倒计时门闩,等待多个线程完成
• CyclicBarrier:循环屏障,让一组线程达到屏障后继续执行
• Semaphore:信号量,控制同时访问特定资源的线程数
int threadCount = 3;
CountDownLatch latch = new CountDownLatch(threadCount);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < threadCount; i++) {
pool.execute(() -> {
// 执行任务...
latch.countDown(); // 完成后减1
});
}
latch.await(); // 主线程等待所有子线程完成
System.out.println("所有任务已完成!");
③ 线程池:高效管理并发线程
在多线程面试入门教程中,线程池是避免频繁创建/销毁线程开销的关键。Java通过Executors提供四种预设线程池,但生产环境推荐使用ThreadPoolExecutor自定义配置。
在多线程面试入门教程中,任务队列类型直接影响系统行为:
• ArrayBlockingQueue:有界队列,防止OOM
• LinkedBlockingQueue:默认无界,易OOM
• SynchronousQueue:无存储,直接提交给线程
• PriorityBlockingQueue:优先级队列
在多线程面试入门教程中,推荐配置策略:
• CPU密集型任务:线程数 ≈ CPU核心数 + 1
• IO密集型任务:线程数 ≈ CPU核心数 × 2
• 拒绝策略:优先使用CallerRunsPolicy(让调用者线程执行任务)
int cpuCores = Runtime.getRuntime().availableProcessors();
BlockingQueue queue = new ArrayBlockingQueue<>(1000);
ThreadFactory factory = new ThreadFactoryBuilder()
.setNameFormat("biz-pool-%d")
.setDaemon(true)
.build();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
cpuCores * 2,
cpuCores * 2,
60L, TimeUnit.SECONDS,
queue,
factory,
new ThreadPoolExecutor.CallerRunsPolicy()
);
④ 死锁处理:检测、预防与诊断
死锁的四大必要条件
在多线程面试入门教程中,死锁是并发编程的“经典噩梦”。其产生需同时满足:
① 互斥条件:资源不可共享
② 请求与保持:线程持有资源同时申请新资源
③ 不可剥夺:资源不能被强制释放
④ 循环等待:存在线程间资源环形依赖
死锁检测与诊断工具
在多线程面试入门教程中,排查死锁的常用方法:
• jstack:生成线程栈,查找BLOCKED状态线程及锁信息
• jconsole:可视化工具,实时监控线程状态
• jcmd:通过jcmd PID Thread.print输出线程信息
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f... nid=0x1a2b waiting for monitor entry [0x00007f...]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadlockDemo.method2(DeadlockDemo.java:20)
- waiting to lock <0x000000076b8c1234> (a java.lang.Object)
- locked <0x000000076b8c5678> (a java.lang.Object)
"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f... nid=0x1a2a waiting for monitor entry [0x00007f...]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadlockDemo.method1(DeadlockDemo.java:10)
- waiting to lock <0x000000076b8c5678> (a java.lang.Object)
- locked <0x000000076b8c1234> (a java.lang.Object)
Found 1 deadlock.
预防死锁的五大策略
在多线程面试入门教程中,预防死锁的工程实践:
① 锁排序:统一获取锁的顺序(如按对象哈希码排序)
② 超时锁:使用tryLock(long timeout, TimeUnit unit)
③ 减少锁粒度:拆分大锁为多个小锁
④ 使用并发容器:如ConcurrentHashMap替代synchronized Map
⑤ 避免嵌套锁:重构代码减少锁嵌套层级
⑤ 多线程面试高频问题FAQ
• AbortPolicy:抛出RejectedExecutionException(默认)
• CallerRunsPolicy:由调用线程执行任务(推荐)
• DiscardPolicy:直接丢弃任务
• DiscardOldestPolicy:丢弃队列最老任务
金融/交易系统建议用CallerRunsPolicy避免任务静默丢失。
1. top -p PID 查看线程ID(十进制)
2. printf "%x\n" 线程ID 转为十六进制
3. jstack PID | grep hexThreadID -A 10 查看线程栈
重点分析BLOCKED或RUNNABLE状态线程的调用栈,定位热点代码。
• 在任务中显式try-catch
• 自定义ThreadFactory设置UncaughtExceptionHandler
• 使用CompletableFuture的exceptionally处理异常