Java并发基础+进阶 小白完整版(统一是什么+为什么+怎么运行) 一、Java并发基础核心知识点面试必考1. 线程6大生命周期状态是什么为什么怎么运行1.1 是什么线程从创建、运行、阻塞到最终死亡的完整过程一共固定6种状态是Java线程运行的基础规则所有线程的行为都离不开这6种状态。六大状态详细定义① NEW新建状态代码执行new Thread()创建线程对象仅完成实例化未调用start()线程只是一个空对象不具备运行资格。② RUNNABLE可运行状态线程调用start()后进入该状态包含两种场景排队等待CPU资源、正在CPU中执行代码。③ BLOCKED锁阻塞状态多线程争抢synchronized同步锁失败主动停下来等待其他线程释放锁。④ WAITING无限等待状态线程调用wait()、join()主动休眠挂起无固定等待时间。⑤ TIMED_WAITING限时等待状态线程调用sleep()、带超时的 wait/join有固定休眠时间。⑥ TERMINATED终止状态线程代码执行完毕或异常终止生命周期彻底结束。1.2 为什么要设计6种线程状态为了精准管控多线程执行顺序、资源占用和等待逻辑。如果没有状态区分线程会混乱抢占CPU资源无法实现等待、阻塞、休眠等功能多线程并发会完全失控无法保证线程安全和程序稳定性。1.3 怎么运行状态切换流程1. 代码创建线程对象 →NEW 新建2. 调用start()启动线程 →RUNNABLE 可运行3. 抢锁失败 →BLOCKED 阻塞抢到锁继续运行4. 主动调用无超时等待方法 →WAITING 无限等待需手动唤醒后回到RUNNABLE5. 主动调用限时等待方法 →TIMED_WAITING 限时等待时间结束自动回到RUNNABLE6. 代码执行完成/异常退出 →TERMINATED 终止死亡记忆口诀新建就绪运行中阻塞等待分两种限时自动来唤醒运行结束就终止。2. synchronized 和 Lock 核心区别统一模板2.1 是什么两者都是Java中保证线程安全、解决并发争抢问题的锁工具synchronizedJVM底层自带的锁关键字属于系统级自动锁。LockJava提供的API手动锁接口属于代码可控的工具锁。2.2 为什么需要两种锁1. synchronized 开箱即用、简单省心适合大部分普通并发场景不用手动管控锁2. Lock 功能更强大、更灵活可解决 synchronized 无法实现的场景比如可中断等待、公平锁、精准唤醒线程适配复杂高并发业务。2.3 怎么运行核心差异运行逻辑1. 底层运行逻辑synchronized自动加锁、自动释放锁JVM全程管控无需手动干预。Lock必须手动调用lock()上锁、unlock()解锁解锁必须放在finally中防止异常导致锁无法释放。2. 公平性运行逻辑synchronized固定非公平锁线程随机抢锁允许插队。Lock可手动指定公平/非公平锁适配不同业务需求。3. 中断运行逻辑synchronized线程抢锁失败只能死等无法中断阻塞状态。Lock可通过lockInterruptibly()响应中断线程不想等待可直接退出避免卡死。4. 队列唤醒运行逻辑synchronized只有1个等待队列唤醒只能全部唤醒造成大量无效竞争。Lock支持多个Condition队列可精准唤醒指定业务线程性能更高。5. 性能运行逻辑JDK1.6后 synchronized 新增锁升级优化偏向锁、轻量级锁、重量级锁性能大幅提升和Lock几乎持平。记忆口诀关键字自动锁API手动锁公平可选择中断Lock行单多队列有差异1.6之后性能近。3. volatile 关键字统一模板3.1 是什么volatile 是Java轻量级并发关键字专门解决多线程的可见性、指令重排序问题不保证原子性是锁的轻量化补充工具。3.2 为什么需要volatile多线程下CPU缓存和编译器优化会导致两个严重问题1. 线程缓存变量看不到其他线程修改的最新数据可见性问题2. CPU、编译器乱序执行代码出现意想不到的BUG指令重排问题volatile 专门解决这两个问题开销比锁小、性能更高适合简单并发场景。3.3 怎么运行核心工作原理1. 保证可见性运行逻辑普通变量线程读取数据走自己的工作内存修改后不会立刻同步主内存其他线程看不到最新值。volatile变量任意线程修改后立刻刷新到主内存其他线程读取时直接读主内存最新数据全员数据同步。2. 禁止指令重排序运行逻辑通过插入内存屏障强制固定代码执行顺序禁止CPU和编译器打乱指令执行步骤杜绝重排BUG典型应用DCL单例模式。核心限制必记volatile 只能保证单步读写安全像 i读算写复合操作无法保证原子性多线程依然数据错乱不能替代锁。记忆口诀可见、禁重排原子性它来不了单变量读写可用复合操作要上锁。4. 基础自测练习题小白易懂答案1. 线程有哪6种状态调用sleep()会进入什么状态答NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATEDsleep() 进入限时等待状态 TIMED_WAITING时间到自动唤醒。2. synchronized为什么不能中断等待Lock如何实现可中断等待答synchronized由JVM底层管控阻塞等待无法手动中断Lock提供可中断抢锁方法能让阻塞线程中途退出避免线程卡死。3. volatile可以保证原子性吗为什么答不可以。自增等复合操作分为读取、运算、写入三步volatile只能保证单步数据可见无法锁住整套操作多线程会出现数据错乱。4. DCL单例为什么要用volatile修饰实例对象答防止指令重排序避免其他线程获取到未初始化完成的半空对象杜绝空指针异常。二、Java并发进阶高频知识点全文统一模板1. 线程状态进阶深挖1.1 RUNNABLE状态是什么为什么怎么运行是什么Java独有的可运行状态包含操作系统的「就绪态」和「运行态」两种状态。为什么这么设计操作系统区分两种状态过于繁琐Java为了简化线程模型统一合并为RUNNABLE降低开发和学习成本。怎么运行调用start()后线程进入就绪队列排队拿到CPU时间片则运行代码全程都属于RUNNABLE状态。1.2 三大等待状态区别BLOCKED / WAITING / TIMED_WAITING是什么三种都是线程暂停运行的状态区别在于触发条件、等待方式、唤醒规则不同。为什么区分三种状态适配不同业务等待场景区分「被动抢锁等待」和「主动休眠等待」方便JVM精准调度线程、优化性能。怎么运行BLOCKED抢synchronized锁失败被动等待别人释放锁锁到手立刻恢复运行。WAITING主动休眠无限等待必须其他线程手动唤醒才能恢复。TIMED_WAITING主动限时休眠时间结束自动唤醒无需他人干预。记忆口诀锁抢不到进阻塞主动等待分两种无限要唤醒限时自动醒。1.3 线程能否二次start()是什么线程生命周期唯一只能启动一次。为什么不允许二次启动线程终止后资源已释放、状态已固化二次启动会造成线程状态混乱、资源冲突。怎么运行线程执行完毕进入TERMINATED状态再次调用start()直接抛出异常。2. synchronized 锁升级原理2.1 锁升级机制是什么JDK1.6对synchronized做的核心优化锁会根据线程竞争激烈程度自动从低性能层级升级到高性能层级分为偏向锁→轻量级锁→重量级锁只能升级、不能降级。2.2 为什么要锁升级适配不同并发场景单线程无竞争用最轻量的偏向锁、轻微竞争用自旋轻量级锁、激烈竞争用重量级锁最大化提升synchronized整体性能缩小和Lock的差距。2.3 怎么运行完整升级流程1. 偏向锁单线程无竞争JVM记录唯一执行线程ID后续该线程直接获取锁无需校验争抢性能最高。2. 轻量级锁轻微多线程竞争偏向锁撤销升级线程通过CAS自旋循环抢锁不进入操作系统阻塞开销极低。3. 重量级锁激烈竞争自旋多次抢锁失败升级为系统内核锁抢不到锁的线程进入阻塞队列停止空转消耗CPU。记忆口诀单线程偏向多线程轻量自旋失败重量锁只能升级不能降。2.4 可重入锁原理是什么synchronized和ReentrantLock都支持可重入同一线程可多次获取同一把锁。为什么需要可重入避免同一线程嵌套加锁时自我死锁适配嵌套同步代码的业务场景。怎么运行底层依靠锁计数器加锁1、释放-1计数器归0锁才真正释放。3. Lock 进阶核心3.1 公平锁 非公平锁是什么Lock锁的两种抢锁规则控制多线程抢锁是否排队synchronized仅支持非公平锁。为什么设计两种模式非公平锁追求高性能、高吞吐量公平锁追求线程公平、杜绝线程饥饿适配不同业务需求。怎么运行非公平锁新线程优先CAS插队抢锁抢到即执行抢不到再排队性能高可能出现线程饥饿。公平锁严格先来后到新线程直接入队不插队所有线程都能执行吞吐量略低。3.2 tryLock() 方法是什么Lock独有非阻塞抢锁方法尝试抢锁返回布尔结果不阻塞线程。为什么需要普通锁会无限阻塞线程容易死锁、卡死tryLock可主动放弃抢锁规避并发死锁风险。怎么运行调用瞬间尝试抢锁成功执行业务失败直接退出线程不阻塞、可继续执行其他逻辑。3.3 多Condition多队列机制是什么一把Lock锁可创建多个独立等待队列不同业务线程对应不同队列休眠。为什么需要synchronized单队列只能全部唤醒大量无效唤醒浪费CPU多队列可精准唤醒提升并发性能。怎么运行不同业务线程进入对应队列等待触发业务逻辑时仅唤醒目标队列线程其他线程持续休眠。4. volatile 深度进阶4.1 内存屏障原理是什么volatile底层依靠四种内存屏障LoadLoad、LoadStore、StoreStore、StoreLoad禁止指令重排、保证可见性。为什么需要内存屏障CPU和编译器为提速会乱序执行代码内存屏障强制固定执行顺序、强制刷新主内存数据。怎么运行读写volatile变量时插入屏障前面代码执行完毕后才执行当前代码禁止指令跨越重排。4.2 为什么volatile不保证原子性是什么原子性是指一组操作不可分割、要么全成要么全败volatile无法满足。为什么无法保证i等复合操作分三步读、算、写volatile仅保证单步可见无法锁住整套操作多线程会穿插执行导致数据错乱。怎么解决使用synchronized、Lock、Atomic原子类保证原子性。4.3 DCL单例必须加volatile的原因是什么DCL双重检查锁是单例模式常用写法必须搭配volatile使用。为什么必须加防止对象创建指令重排避免出现「半空对象」引发空指针异常。怎么运行不加volatile会重排为分配内存→赋值引用→初始化对象加volatile固定顺序分配内存→初始化对象→赋值引用保证对象完整可用。4.4 volatile典型使用场景线程停止状态标记、DCL单例模式、观察者模式开关仅简单读写场景不做复合运算。5. 多线程三大核心安全问题5.1 可见性、原子性、有序性统一模板是什么多线程并发的三大核心安全隐患所有线程安全问题都源于这三点。为什么会出现三大问题JVM内存模型、CPU缓存机制、指令重排优化导致多线程数据不同步、操作错乱、顺序混乱。怎么解决怎么运行规避问题可见性volatile、synchronized、Lock 强制刷新主内存数据。原子性synchronized、Lock、原子类 锁住整套操作保证不可分割。有序性volatile、synchronized 禁止指令重排固定执行顺序。记忆口诀可见靠屏障原子要上锁有序禁重排三性保安全。6. 线程通信进阶6.1 sleep 和 wait 区别是什么两个都是线程休眠方法底层机制、锁行为、使用场景完全不同。为什么需要两种方法sleep用于单纯定时休眠wait用于多线程通信等待适配不同业务休眠场景。怎么运行核心区别1. 归属不同sleep是Thread静态方法wait是Object方法。2. 锁机制不同sleep不释放锁wait必须在同步块执行、会主动释放锁。3. 唤醒方式不同sleep时间到自动醒wait必须手动notify唤醒。4. 使用范围不同sleep任意场景可用wait只能在同步代码块中使用。6.2 LockSupport 线程等待唤醒是什么Java新一代线程等待唤醒工具park/unpark。为什么要用解决wait/notify的BUG避免先唤醒后等待导致线程永久阻塞。怎么运行无需依赖同步锁先park休眠、后unpark唤醒或者先unpark、后park都能正常响应线程通信更稳定。7. 进阶高频面试题小白易懂答案1. 偏向锁什么时候会被撤销答出现其他线程竞争偏向锁、线程调用hashCode()、JVM启动延迟加载偏向锁时都会撤销偏向锁升级为轻量级锁。2. 什么是线程饥饿怎么避免答大量新线程插队导致老线程长期抢不到锁、一直等待就是线程饥饿使用公平锁可以完美避免。3. volatile修饰计数器自增为什么结果错误怎么解决答volatile不保证原子性无法锁住读改写三步操作解决方案synchronized、ReentrantLock、AtomicInteger原子类。4. synchronized有哪些锁优化答偏向锁、轻量级锁、自适应自旋、锁粗化、锁消除大幅提升锁性能。