JUC并发编程【八股篇】:并发基础

发布时间:2026/7/8 6:17:14

JUC并发编程【八股篇】:并发基础 JUC并发编程【八股篇】并发基础这是JUCjava.util.concurrent并发编程系列的基础篇主要梳理面试高频的“并发八股”核心概念。后续会继续讲锁机制、AQS、线程池、并发工具类、原子类等。内容以原理 面试问法 背诵要点为主帮助你快速掌握并发编程的根基。1. 进程 vs 线程必考基础进程操作系统资源分配的基本单位。每个进程拥有独立的地址空间、内存、文件句柄等资源。进程之间相互隔离通信开销大管道、消息队列、共享内存等。线程操作系统调度CPU时间片分配的最小单位。线程是进程内的执行单元多个线程共享进程的地址空间和资源堆、方法区、文件描述符等但每个线程有自己独立的程序计数器、栈、寄存器防止互相干扰。区别总结进程资源拥有者隔离性强开销大。线程调度单位轻量级共享资源开销小但容易出现线程安全问题。一个进程至少有一个线程主线程Java中线程由JVM管理但底层映射到OS线程HotSpot中是1:1模型。面试追问Java线程和OS线程的关系→ Java线程最终依赖OS原生线程实现pthread或Windows线程。为什么多线程能提高效率→ 充分利用多核CPU、隐藏IO等待并发 vs 并行。2. 并发Concurrency vs 并行Parallelism并发多个任务在同一时间段内交替执行单核CPU通过时间片轮转实现。重点是“同时段”。并行多个任务在同一时刻真正同时执行多核CPU。重点是“同时点”。举例单核CPU跑多个线程 → 并发。多核CPU每个核跑一个线程 → 并行。为什么需要并发编程充分利用多核CPU性能。业务拆分提升响应速度IO密集型任务特别明显。异步处理、提高吞吐量。并发编程的缺点线程安全问题原子性、可见性、有序性被破坏。上下文切换开销频繁切换线程保存/恢复寄存器、程序计数器等。死锁、活锁、饥饿等问题。调试困难非确定性。3. 并发编程三大特性核心线程安全必须同时满足以下三点原子性Atomicity一个操作要么全部执行成功要么全部不执行。中间状态对外不可见。经典破坏i实际是读-改-写三步非原子。保证手段synchronized、Lock、Atomic原子类、CAS。可见性Visibility一个线程修改共享变量后其他线程能立即看到最新值。破坏原因CPU缓存、编译器/CPU重排序、JMM工作内存。保证手段volatile、synchronized、final、Lock、Happens-Before。有序性Ordering程序执行的顺序按照代码的先后顺序执行禁止重排序影响结果。as-if-serial单线程看起来像串行执行。破坏编译器/JIT/CPU重排序。保证手段volatile、synchronized、Happens-Before。面试常问并发编程三要素是什么如何保证4. Java内存模型JMM—— 并发编程的灵魂JMM是Java虚拟机规范定义的抽象内存模型屏蔽了不同硬件/OS的内存差异。主内存所有线程共享对应堆、方法区。工作内存本地内存每个线程私有的缓存对应栈 CPU缓存线程操作变量时先从主内存拷贝到工作内存。JMM三大特性原子性针对基本操作。可见性。有序性通过Happens-Before保证。重排序编译器、处理器为了优化性能可能改变指令执行顺序。但必须遵守as-if-serial单线程语义不改变和Happens-Before。5. Happens-Before原则JMM最核心规则如果操作AHappens-Before操作B则A的结果对B可见。A的执行顺序在B之前即使实际可能重排序但结果必须一致。8大Happens-Before规则背诵重点程序次序规则同一个线程内代码按书写顺序执行前面的Happens-Before后面的。监视器锁规则synchronized对同一个锁的unlock操作Happens-Before后续的lock操作。volatile变量规则对volatile变量的写操作Happens-Before后续的读操作。传递性如果A HB BB HB C则A HB C。线程启动规则Thread.start() Happens-Before 该线程run()中的任何操作。线程终止规则线程中所有操作Happens-Before其他线程检测到该线程终止join()返回、isAlive()false。线程中断规则interrupt()调用Happens-Before被中断线程检测到中断isInterrupted()。对象终结规则一个对象的构造完成Happens-Before其finalize()开始。面试追问volatile为什么能保证可见性和有序性依赖volatile写-读的Happens-Before 内存屏障6. 线程的生命周期与状态5种或6种状态Java线程状态Thread.State枚举NEW新建状态创建Thread对象但未start()。RUNNABLE就绪/运行状态包含OS的Ready和Running。start()后进入。BLOCKED阻塞状态等待获取monitor锁如synchronized未获取。WAITING无限等待Object.wait()、Thread.join()、LockSupport.park()。TIMED_WAITING超时等待Thread.sleep()、wait(long)、join(long)。TERMINATED终止状态run()执行完或异常退出。状态转换图经典面试题NEW → start() → RUNNABLERUNNABLE → 阻塞/等待 → BLOCKED/WAITING/TIMED_WAITING唤醒后 → RUNNABLE结束 → TERMINATED注意RUNNABLE不等于正在CPU上运行可能在就绪队列等待时间片。7. 创建线程的几种方式及优缺点继承Thread类重写run()。简单但不推荐单继承限制任务与线程耦合。实现Runnable接口实现run()传给Thread。推荐解耦。实现Callable接口 FutureTask有返回值可抛异常。结合线程池使用。线程池推荐Executors或ThreadPoolExecutor。复用线程管理线程生命周期控制并发数。为什么不推荐直接new Thread频繁创建/销毁开销大。无法统一管理资源耗尽风险。线程池可复用、限流、优雅关闭。8. 上下文切换Context Switch定义CPU从一个线程切换到另一个线程时需要保存当前线程的执行上下文寄存器、程序计数器、栈指针等加载目标线程的上下文。开销耗费CPU时间微秒级频繁切换会降低整体性能。导致原因时间片用完、阻塞、yield、优先级等。优化减少锁竞争、合理使用线程数CPU密集型 ≈ 核数IO密集型 ≈ 核数 * 2~4、使用协程虚拟线程JDK21。9. 死锁Deadlock及避免死锁四个必要条件Coffman条件互斥条件资源独占。请求并持有条件已持有资源还请求其他。不可剥夺条件资源只能主动释放。循环等待条件形成环。如何避免破坏一个条件即可如按固定顺序申请锁、超时获取锁、资源一次性分配。常用tryLock()带超时、ReentrantLock、避免嵌套锁。排查jstack、jconsole、VisualVM查看线程dump找“waiting for”循环。10. 其他基础概念线程安全多个线程同时访问共享数据时结果与单线程执行一致。重入锁同一个线程可重复获取已持有的锁synchronized、ReentrantLock都支持。守护线程Daemon为用户线程服务的线程GC线程主线程结束时自动终止。setDaemon(true)必须在start()前调用。ThreadLocal线程本地变量每个线程独立副本后续会详细讲内存泄漏问题。并发基础总结口诀便于背诵进程资源分配线程CPU调度共享内存有风险三性必须保JMM主从内存HB先行可见线程五态转锁争上下文耗死锁四条件破坏一即可。掌握以上内容你就有了并发编程的坚实根基。下一期我们将深入锁机制synchronized底层、锁升级、ReentrantLock、AQS原理。如果你想看手绘图、具体代码示例、或某部分更详细展开比如Happens-Before具体例子随时告诉我也可以直接问“JUC八股 锁篇”或具体面试题。

相关新闻