当前位置: 首页 > news >正文

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 无限等待,需手动唤醒后回到RUNNABLE

5. 主动调用限时等待方法 →TIMED_WAITING 限时等待,时间结束自动回到RUNNABLE

6. 代码执行完成/异常退出 →TERMINATED 终止死亡

记忆口诀:新建就绪运行中,阻塞等待分两种,限时自动来唤醒,运行结束就终止。


2. synchronized 和 Lock 核心区别(统一模板)

2.1 是什么

两者都是Java中保证线程安全、解决并发争抢问题的锁工具:

synchronized:JVM底层自带的锁关键字,属于系统级自动锁。

Lock:Java提供的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、TERMINATED;sleep() 进入限时等待状态 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有哪些锁优化?

答:偏向锁、轻量级锁、自适应自旋、锁粗化、锁消除,大幅提升锁性能。

http://www.jsqmd.com/news/1069197/

相关文章:

  • 数字人直播哪个公司好
  • AI写教材必备攻略:掌握技巧,借助工具达成低查重教材编写
  • 终极指南:用TegraRcmGUI轻松解锁Switch隐藏功能
  • AI任务分类与需求分析
  • 3分钟搞定!TranslucentTB让Windows任务栏变身透明神器
  • WechatApi客户管理与 AI 客服如何深度融合?
  • 微信数据自主管理终极方案:WeChatExporter一站式备份与导出实战指南
  • 从17.3%到40.3%:企业AI Agent加速落地后,运行安全会成为分水岭
  • 从产品想法到专利保护,AI专利撰写工具能做什么?
  • 背包九讲完全背包 转化为01背包问题求解 数学原理
  • 昇腾CANN信号处理加速库sip的FFT变换BLAS向量运算FIR数字滤波算子性能瓶颈分析方法与基带数据处理器实战部署系统优化策略方案
  • Sunshine游戏串流技术架构深度解析:自托管流媒体服务器实现原理
  • 贵阳纳海川科技·数智校园
  • 终极窗口置顶工具:PinWin让你工作效率飙升3倍的完整指南
  • EditPlus安装教程详细步骤EditPlus v6下载安装汉化教程
  • 2026年外贸网站平台都有哪些?
  • 抖音无水印下载神器:5分钟掌握批量下载全攻略
  • Cursor入门 07 - 大模型自由切换
  • 如何为工业级大规模逻辑应用选择FPGA?XC6SLX150-2FGG900I的147K LE与-40°C~100°C宽温方案解析
  • 沙海远征 向死而生|雨帆铁军108KM戈壁徒步穿越之旅破局出发
  • 抖音无水印视频下载器:专业开源工具深度解析与技术实现
  • 无人机视角建筑外立面裂缝鼓包剥落缺陷检测数据集VOC+YOLO格式14295张6类别
  • 云客服和传统呼叫中心有什么区别?企业升级前必看的 5 个核心差异
  • WaveTools:3分钟快速上手,让《鸣潮》游戏体验提升42%的终极工具箱
  • Sunshine游戏串流完全指南:5步搭建你的家庭游戏云
  • Mac启动Shizuku
  • Cursor入门 09 - 与 Git 深度协作
  • StreamCap终极指南:如何免费录制40+平台直播内容
  • 增值税应用服务器频繁卡死 全量会话分析1小时定位代码逻辑缺陷
  • 快充协议测试技术全解析:QC/PD/SCP/FCP,到底怎么测?