1-3-1-知识图谱

Java并发编程的知识体系确实庞大且环环相扣。下面我为你梳理一个结构清晰的知识图谱,并附上核心要点和面试考察方向,希望能帮助你系统性地复习和准备。

🧠 Java并发编程知识图谱:从理论到实战

📚 1. 并发基础与理论基石

要理解并发,首先要掌握它的三大核心概念和Java内存模型。

  • 并发三要素
    • 原子性:操作要么全部成功,要么全部失败,不可中断。例如,count++不是原子操作。
    • 可见性:一个线程对共享变量的修改,能立刻被其他线程看到。volatile关键字是解决可见性的常用手段。
    • 有序性:程序执行的顺序按照代码的先后顺序。编译器和处理器可能会指令重排序volatilesynchronized能防止其发生。
  • Java内存模型(JMM):JMM规定了线程如何与主内存交互。它定义了主内存(共享变量存储区)和每个线程的工作内存(私有变量副本)。线程对变量的操作首先在工作内存中进行,然后刷回主内存。这导致了可见性问题,而 Happens-Before 原则是JMM用于保证操作可见性的重要规则。

🔐 2. 线程管理与生命周期

  • 创建方式:继承 Thread类或实现 RunnableCallable接口。后者更灵活,允许继承其他类,并且 Callable可以返回结果和抛出异常。
  • 线程状态:Java线程在其生命周期中会处于不同的状态。
    • NEW(新建):线程被创建但尚未启动。
    • RUNNABLE(可运行):正在运行或准备运行,等待CPU调度。
    • BLOCKED(阻塞):等待获取一个监视器锁(如进入synchronized块)。
    • WAITING(无限期等待):等待另一个线程执行特定操作(如 object.wait())。
    • TIMED_WAITING(限期等待):带超时时间的等待(如 Thread.sleep(time))。
    • TERMINATED(终止):线程执行完毕。
  • 重要方法
    • wait(), notify(), notifyAll():用于线程间协作,必须在 synchronized块内调用,且会释放锁。
    • sleep():暂停线程执行,不释放任何锁。
    • yield():提示调度器愿意让出CPU,但不保证成功。
    • join():等待目标线程终止后再继续执行。

⚔️ 3. 同步机制与锁

这是并发编程的核心,也是面试的重点考察区。

  • synchronized

    • 用法:修饰实例方法、静态方法、代码块。

    • 底层原理:基于对象头中的 Mark WordMonitor(管程)机制。JVM对其进行了大量优化,锁会根据竞争情况升级:

      无锁 → 偏向锁 → 轻量级锁(CAS自旋) → 重量级锁

    • 特点:JVM负责加锁和释放锁,简单易用。

  • JUC Locks

    • ReentrantLock:可重入的互斥锁,相比 synchronized功能更丰富。
      • 支持公平锁非公平锁(默认)。
      • 尝试非阻塞获取锁tryLock())。
      • 响应中断lockInterruptibly())。
      • 可以绑定多个条件变量(Condition),实现更精细的线程等待与唤醒。
    • ReadWriteLock:读写锁,实现读-读不互斥,读-写、写-写互斥,适合读多写少的场景。
    • StampedLock(JDK8+):提供三种模式的锁控制。乐观读是其一大亮点,在竞争不激烈时能极大提升读性能。
  • 底层基石:AQS (AbstractQueuedSynchronizer)

    • 它是 ReentrantLock, CountDownLatch, Semaphore等众多同步工具的底层实现核心。
    • 它通过一个 FIFO双向队列(CLH变体) 来管理等待获取资源的线程,并使用一个 volatile int state变量来表示同步状态。

🧪 4. 原子变量与无锁编程

  • CAS (Compare-And-Swap):一种无锁的乐观并发策略。它包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。当且仅当V的值等于A时,才会用B更新V的值。这是一个CPU硬件指令,保证了原子性。
  • 原子类java.util.concurrent.atomic包下的类,如 AtomicInteger, AtomicReference,利用CAS实现线程安全的原子操作。
    • ABA问题:一个值从A变成B,又变回A,CAS会误以为它没变过。解决方案是使用带版本号的 AtomicStampedReference
    • LongAdder:在高并发争用下,它将热点数据分离成多个Cell,让线程分散竞争,最后汇总结果。性能通常优于 AtomicLong

🧰 5. 并发工具类 (JUC)

Java提供了强大的工具类来简化复杂的线程协作。

工具类 核心用途 特点
CountDownLatch 让一个或多个线程等待一组其他线程完成操作 一次性使用,计数减到0后,等待线程继续执行。
CyclicBarrier 让一组线程相互等待,到达一个公共屏障点后再继续执行 可重置,可循环使用,支持设置到达屏障后的统一任务(Runnable)。
Semaphore 控制同时访问特定资源的线程数量 用于流量控制、资源池化(如数据库连接池)。
Phaser 更灵活、可重用的同步屏障 支持动态调整注册的线程数,支持多阶段(Phase)同步。

🚀 6. 线程池与执行框架

手动创建和管理线程代价高昂,线程池是更好的选择。

  • 核心类ThreadPoolExecutor是线程池的实现核心。
  • 核心参数(7大参数)
    1. corePoolSize:核心线程数,即使空闲也不会被回收。
    2. maximumPoolSize:线程池允许创建的最大线程数。
    3. keepAliveTime:非核心线程空闲后的存活时间。
    4. workQueue:任务队列,用于保存等待执行的任务。
      • ArrayBlockingQueue:有界队列。
      • LinkedBlockingQueue:无界队列(需警惕任务堆积)。
      • SynchronousQueue:不存储元素,每个插入操作必须等待另一个线程的移除操作。
    5. threadFactory:用于创建新线程的工厂。
    6. RejectedExecutionHandler拒绝策略,当线程池和队列都已满时如何处理新任务。
      • AbortPolicy(默认):抛出 RejectedExecutionException
      • CallerRunsPolicy:由提交任务的线程自己执行该任务。
      • DiscardPolicy:直接丢弃任务。
      • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试提交新任务。
  • 工作流程
    1. 提交新任务。
    2. 若当前线程数 < corePoolSize,立即创建新线程执行。
    3. 若已达到 corePoolSize,则将任务放入 workQueue。
    4. 若队列已满且当前线程数 < maximumPoolSize,创建新的非核心线程执行。
    5. 若队列已满且线程数已达 maximumPoolSize,触发拒绝策略。
  • 配置建议
    • CPU密集型(计算为主):corePoolSize = CPU核数 + 1
    • IO密集型(网络、磁盘IO为主):corePoolSize = CPU核数 * 2
    • 最佳实践:使用有界队列,并自定义线程工厂(给线程命名,便于排查问题)和拒绝策略。

📦 7. 并发集合容器

传统的 HashMap, ArrayList不是线程安全的。JUC提供了高效的并发容器。

  • ConcurrentHashMap:线程安全的HashMap。
    • JDK7:采用分段锁机制,将数据分成一段一段存储,每段配一把锁。
    • JDK8及以后:摒弃分段锁,改用 synchronized锁桶头节点 + CAS 的方式,进一步减小锁粒度,提升并发度。
  • CopyOnWriteArrayList写时复制集合。所有写操作(add, set等)都会复制底层数组,在新数组上修改,最后替换引用。读操作无锁,性能极高,适合读多写少的场景。
  • BlockingQueue阻塞队列,是实现生产者-消费者模式的绝佳工具。常见实现有 ArrayBlockingQueue(有界)、LinkedBlockingQueue(可选有界/无界)、SynchronousQueue(不存元素,直接传递)。

💡 8. 高级主题与最佳实践

  • 死锁与排查
    • 产生条件:互斥、不可剥夺、请求与保持、循环等待。
    • 预防:统一加锁顺序、使用定时锁(tryLock(timeout))、减小锁粒度。
    • 排查:使用 jstack <pid>命令 dump 线程栈,查看线程状态和锁持有信息。
  • 性能优化
    • 减小锁粒度(如 ConcurrentHashMap)。
    • 读写分离(使用 ReadWriteLock)。
    • 使用无锁数据结构(如原子类)。
    • 批量操作合并,减少同步次数。
  • CompletableFuture(JDK8+):强大的异步编程工具,支持链式调用、组合多个异步任务、异常处理等,让异步代码编写更加优雅。

💎 知识图谱总结

知识模块 核心概念/工具 面试考察关键点
并发基础 原子性、可见性、有序性、JMM、Happens-Before volatile关键字的作用(不保证原子性),synchronized的内存语义,指令重排序的影响
线程管理 线程状态(6种)、wait/notify vs sleep/yield/join、守护线程 sleepwait的区别(是否释放锁),startrun方法的区别,如何正确停止线程
锁机制 synchronized锁升级过程、ReentrantLock(公平/非公平、Condition)、AQS原理 AQS队列工作原理,ReentrantLock相比synchronized的优势,自旋锁的优缺点
无锁编程 CAS原理、Atomic系列、LongAdder、ABA问题 CAS的底层CPU指令,AtomicLong在高并发下的瓶颈及LongAdder的解决方案
并发工具类 CountDownLatch/CyclicBarrier/Semaphore/Phaser的区别与使用场景 CountDownLatch(一次性)和CyclicBarrier(可重置)的区别,Semaphore在限流中的应用
线程池 ThreadPoolExecutor七大参数、四种拒绝策略、工作流程、配置原则 核心参数如何设置,非核心线程何时创建,常见的线程池类型(Fixed, Cached)及其潜在问题,如何合理配置线程池大小
并发容器 ConcurrentHashMap(JDK7 vs JDK8)、CopyOnWriteArrayList、BlockingQueue ConcurrentHashMap如何保证线程安全和高性能,CopyOnWriteArrayList的适用场景和缺点,BlockingQueue实现生产者消费者模型
高级主题与实战 死锁预防与排查、CompletableFuture异步编程、性能优化原则 如何用jstack分析死锁,CompletableFuture的任务组合(thenApply, thenCompose, allOf),线上常见并发问题解决方案

希望这份知识图谱能帮助你构建清晰的学习和复习路径。并发编程的掌握离不开动手实践,建议你多写代码,多思考不同场景下的应用与取舍。如果你对某个特定知识点想进行更深入的探讨或模拟面试,我很乐意为你提供帮助。

posted @ 2025-11-11 15:23  哈罗·沃德  阅读(0)  评论(0)    收藏  举报