最近在学习 Java 多线程基础梳理了线程安全产生根源、synchronized 锁用法以及极易踩坑的死锁问题把整套知识点整理成通俗易懂的笔记方便后续复习也分享给正在学多线程的同学一、什么是线程安全多线程程序中多个线程同时访问共享资源如果程序最终运行结果和单线程顺序执行的结果完全一致就代表这段代码是线程安全的反之结果错乱、数据出错就是线程不安全。举个最简单例子多个线程同时累加同一个计数器最终数值和预期不符就是典型的线程安全问题。二、线程安全问题产生的三大核心原因CPU 线程调度具有随机性操作系统随机分配 CPU 时间片线程执行到一半可能被强行切走暂停不会完整走完一整套操作。多线程并发读写同一个共享变量多个线程同时修改同一份公共资源是冲突发生的前提。变量修改操作不具备原子性一行代码底层会拆分成多步 CPU 指令中途可以被打断。 经典示例count并非一步操作底层分为三步把变量值读取到寄存器寄存器完成自增计算将计算结果写回内存保存 线程如果在三步中间被切换就会出现数据覆盖、数值丢失。三、解决线程安全synchronized 同步锁1. 锁的核心作用加锁后同一时刻仅有一个线程能持有锁、执行锁内代码其余线程只能阻塞等待。 语法代码执行到右大括号时会自动释放锁。原理通过锁竞争把并发冲突代码改为串行执行以此保证数据安全但串行会牺牲程序运行效率。2. synchronized 两种使用形式与优缺点修饰整个方法 直接在方法声明前添加synchronized锁范围是整个方法。 缺点粒度太大哪怕方法里大部分代码不需要同步也全部串行执行严重降低并发性能。同步代码块推荐只包裹真正操作共享变量的少量代码其余逻辑正常并发运行兼顾安全与性能。3. 补充关键特性可重入锁synchronized是可重入锁同一个线程拿到一把锁后可以多次重复获取这把锁不会自己阻塞自己。 这个特性能规避单锁嵌套场景下的死锁问题。4. synchronized 自带两大特性也是死锁必要条件互斥性锁同一时间只能被一个线程持有其他线程申请同一锁直接进入阻塞等待。不可抢占锁一旦被线程占用其他线程无法强制抢夺只能等待持有者主动释放。5. 为什么大部分类不自带同步锁加锁会强制部分代码串行直接削弱程序并发高性能优势。 因此 Java 默认集合、工具类都无内置锁由开发者根据业务场景手动选择是否加锁。同时仅靠单锁也有局限如果一段业务需要多把锁共同保证原子操作只加单个同步锁依旧会出现线程安全问题。四、死锁多锁场景下的严重问题1. 死锁定义多个线程互相持有对方需要的锁资源同时又发起请求获取对方手中的锁所有线程无限阻塞、僵持等待程序卡死无法自动恢复。2. 死锁带来的危害问题复现随机性强依赖 CPU 调度顺序测试时很难稳定复现排查难度极高线程永久阻塞持续占用 CPU、内存、连接等系统资源无法主动释放业务流程停滞严重时导致整个服务卡顿、瘫痪。3. 触发死锁的四个必要条件互斥条件synchronized 锁天然满足同一锁只能单线程持有不可抢占条件synchronized 锁天然满足无法强行抢夺他人锁持有并请求条件线程已经持有锁 A不释放又去申请锁 B锁嵌套使用 可重入锁仅解决同一把锁多次获取无法解决多把不同锁嵌套循环等待条件线程之间形成环形等待链线程 1 等线程 2 的锁线程 2 等线程 1 的锁。4. 死锁通用解决办法破坏循环等待条件即可给所有锁统一分配编号规定所有线程必须按锁编号从小到大的顺序申请锁杜绝环形等待。