Java 并发 Bug 深度分析与实战
并发编程中隐藏着各种难以发现的 Bug,本文深入分析 Java 并发编程中常见的问题,包括死锁、竞态条件、内存可见性问题等,并提供实用的排查和解决方案。
Java 并发 Bug 总览
#mermaid-svg-8T5XaxzkprBt4u25{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8T5XaxzkprBt4u25 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8T5XaxzkprBt4u25 .error-icon{fill:#552222;}#mermaid-svg-8T5XaxzkprBt4u25 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8T5XaxzkprBt4u25 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8T5XaxzkprBt4u25 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8T5XaxzkprBt4u25 .marker.cross{stroke:#333333;}#mermaid-svg-8T5XaxzkprBt4u25 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8T5XaxzkprBt4u25 p{margin:0;}#mermaid-svg-8T5XaxzkprBt4u25 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8T5XaxzkprBt4u25 .cluster-label text{fill:#333;}#mermaid-svg-8T5XaxzkprBt4u25 .cluster-label span{color:#333;}#mermaid-svg-8T5XaxzkprBt4u25 .cluster-label span p{background-color:transparent;}#mermaid-svg-8T5XaxzkprBt4u25 .label text,#mermaid-svg-8T5XaxzkprBt4u25 span{fill:#333;color:#333;}#mermaid-svg-8T5XaxzkprBt4u25 .node rect,#mermaid-svg-8T5XaxzkprBt4u25 .node circle,#mermaid-svg-8T5XaxzkprBt4u25 .node ellipse,#mermaid-svg-8T5XaxzkprBt4u25 .node polygon,#mermaid-svg-8T5XaxzkprBt4u25 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8T5XaxzkprBt4u25 .rough-node .label text,#mermaid-svg-8T5XaxzkprBt4u25 .node .label text,#mermaid-svg-8T5XaxzkprBt4u25 .image-shape .label,#mermaid-svg-8T5XaxzkprBt4u25 .icon-shape .label{text-anchor:middle;}#mermaid-svg-8T5XaxzkprBt4u25 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8T5XaxzkprBt4u25 .rough-node .label,#mermaid-svg-8T5XaxzkprBt4u25 .node .label,#mermaid-svg-8T5XaxzkprBt4u25 .image-shape .label,#mermaid-svg-8T5XaxzkprBt4u25 .icon-shape .label{text-align:center;}#mermaid-svg-8T5XaxzkprBt4u25 .node.clickable{cursor:pointer;}#mermaid-svg-8T5XaxzkprBt4u25 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8T5XaxzkprBt4u25 .arrowheadPath{fill:#333333;}#mermaid-svg-8T5XaxzkprBt4u25 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8T5XaxzkprBt4u25 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8T5XaxzkprBt4u25 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8T5XaxzkprBt4u25 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8T5XaxzkprBt4u25 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8T5XaxzkprBt4u25 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8T5XaxzkprBt4u25 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8T5XaxzkprBt4u25 .cluster text{fill:#333;}#mermaid-svg-8T5XaxzkprBt4u25 .cluster span{color:#333;}#mermaid-svg-8T5XaxzkprBt4u25 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8T5XaxzkprBt4u25 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8T5XaxzkprBt4u25 rect.text{fill:none;stroke-width:0;}#mermaid-svg-8T5XaxzkprBt4u25 .icon-shape,#mermaid-svg-8T5XaxzkprBt4u25 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8T5XaxzkprBt4u25 .icon-shape p,#mermaid-svg-8T5XaxzkprBt4u25 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8T5XaxzkprBt4u25 .icon-shape .label rect,#mermaid-svg-8T5XaxzkprBt4u25 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8T5XaxzkprBt4u25 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8T5XaxzkprBt4u25 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8T5XaxzkprBt4u25 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Java 并发 Bug
死锁
锁顺序不一致
循环等待
资源不可抢占
竞态条件
非原子操作
Check-Then-Act
Read-Modify-Write
内存可见性
工作内存缓存
指令重排序
缺少 volatile 或锁
线程池问题
参数配置不当
队列堆积
线程泄漏
异步编程
Future 阻塞
异常丢失
上下文丢失
性能问题
锁竞争
伪共享
上下文切换
一、死锁问题
1.1 什么是死锁
死锁是指两个或多个线程相互等待对方持有的资源,导致所有线程都无法继续执行。
#mermaid-svg-aM4M41YOrilLm3mN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aM4M41YOrilLm3mN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aM4M41YOrilLm3mN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aM4M41YOrilLm3mN .error-icon{fill:#552222;}#mermaid-svg-aM4M41YOrilLm3mN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aM4M41YOrilLm3mN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aM4M41YOrilLm3mN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aM4M41YOrilLm3mN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aM4M41YOrilLm3mN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aM4M41YOrilLm3mN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aM4M41YOrilLm3mN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aM4M41YOrilLm3mN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aM4M41YOrilLm3mN .marker.cross{stroke:#333333;}#mermaid-svg-aM4M41YOrilLm3mN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aM4M41YOrilLm3mN p{margin:0;}#mermaid-svg-aM4M41YOrilLm3mN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aM4M41YOrilLm3mN .cluster-label text{fill:#333;}#mermaid-svg-aM4M41YOrilLm3mN .cluster-label span{color:#333;}#mermaid-svg-aM4M41YOrilLm3mN .cluster-label span p{background-color:transparent;}#mermaid-svg-aM4M41YOrilLm3mN .label text,#mermaid-svg-aM4M41YOrilLm3mN span{fill:#333;color:#333;}#mermaid-svg-aM4M41YOrilLm3mN .node rect,#mermaid-svg-aM4M41YOrilLm3mN .node circle,#mermaid-svg-aM4M41YOrilLm3mN .node ellipse,#mermaid-svg-aM4M41YOrilLm3mN .node polygon,#mermaid-svg-aM4M41YOrilLm3mN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aM4M41YOrilLm3mN .rough-node .label text,#mermaid-svg-aM4M41YOrilLm3mN .node .label text,#mermaid-svg-aM4M41YOrilLm3mN .image-shape .label,#mermaid-svg-aM4M41YOrilLm3mN .icon-shape .label{text-anchor:middle;}#mermaid-svg-aM4M41YOrilLm3mN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aM4M41YOrilLm3mN .rough-node .label,#mermaid-svg-aM4M41YOrilLm3mN .node .label,#mermaid-svg-aM4M41YOrilLm3mN .image-shape .label,#mermaid-svg-aM4M41YOrilLm3mN .icon-shape .label{text-align:center;}#mermaid-svg-aM4M41YOrilLm3mN .node.clickable{cursor:pointer;}#mermaid-svg-aM4M41YOrilLm3mN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aM4M41YOrilLm3mN .arrowheadPath{fill:#333333;}#mermaid-svg-aM4M41YOrilLm3mN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aM4M41YOrilLm3mN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aM4M41YOrilLm3mN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aM4M41YOrilLm3mN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aM4M41YOrilLm3mN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aM4M41YOrilLm3mN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aM4M41YOrilLm3mN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aM4M41YOrilLm3mN .cluster text{fill:#333;}#mermaid-svg-aM4M41YOrilLm3mN .cluster span{color:#333;}#mermaid-svg-aM4M41YOrilLm3mN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aM4M41YOrilLm3mN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aM4M41YOrilLm3mN rect.text{fill:none;stroke-width:0;}#mermaid-svg-aM4M41YOrilLm3mN .icon-shape,#mermaid-svg-aM4M41YOrilLm3mN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aM4M41YOrilLm3mN .icon-shape p,#mermaid-svg-aM4M41YOrilLm3mN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aM4M41YOrilLm3mN .icon-shape .label rect,#mermaid-svg-aM4M41YOrilLm3mN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aM4M41YOrilLm3mN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aM4M41YOrilLm3mN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aM4M41YOrilLm3mN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 持有
等待
持有
等待
被线程 1 占用
被线程 2 占用
线程 1
lockA
lockB
线程 2
java
/**
* 经典死锁示例
*/
public class DeadLockDemo {
private static final Object lockA = new Object();
private static final Object lockB = new Object();
public static void main(String[] args) {
// 线程1:先获取lockA,再获取lockB
Thread thread1 = new Thread(() -> {
synchronized (lockA) {
System.out.println("线程1获取到了lockA");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
synchronized (lockB) {
System.out.println("线程1获取到了lockB");
}
}
});
// 线程2:先获取lockB,再获取lockA
Thread thread2 = new Thread(() -> {
synchronized (lockB) {
System.out.println("线程2获取到了lockB");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
synchronized (lockA) {
System.out.println("线程2获取到了lockA");
}
}
});
thread1.start();
thread2.start();
// 可能出现死锁:线程1持有lockA等待lockB,线程2持有lockB等待lockA
}
}
1.2 死锁的四个必要条件
- 互斥条件:资源一次只能被一个线程持有
- 持有并等待:线程持有资源的同时请求其他资源
- 不可抢占:资源不能被强制从持有线程中抢占
- 循环等待:存在线程资源的循环等待链
#mermaid-svg-1IWPJQI4IKy5VvH7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1IWPJQI4IKy5VvH7 .error-icon{fill:#552222;}#mermaid-svg-1IWPJQI4IKy5VvH7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1IWPJQI4IKy5VvH7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .marker.cross{stroke:#333333;}#mermaid-svg-1IWPJQI4IKy5VvH7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1IWPJQI4IKy5VvH7 p{margin:0;}#mermaid-svg-1IWPJQI4IKy5VvH7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster-label text{fill:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster-label span{color:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster-label span p{background-color:transparent;}#mermaid-svg-1IWPJQI4IKy5VvH7 .label text,#mermaid-svg-1IWPJQI4IKy5VvH7 span{fill:#333;color:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .node rect,#mermaid-svg-1IWPJQI4IKy5VvH7 .node circle,#mermaid-svg-1IWPJQI4IKy5VvH7 .node ellipse,#mermaid-svg-1IWPJQI4IKy5VvH7 .node polygon,#mermaid-svg-1IWPJQI4IKy5VvH7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .rough-node .label text,#mermaid-svg-1IWPJQI4IKy5VvH7 .node .label text,#mermaid-svg-1IWPJQI4IKy5VvH7 .image-shape .label,#mermaid-svg-1IWPJQI4IKy5VvH7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-1IWPJQI4IKy5VvH7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .rough-node .label,#mermaid-svg-1IWPJQI4IKy5VvH7 .node .label,#mermaid-svg-1IWPJQI4IKy5VvH7 .image-shape .label,#mermaid-svg-1IWPJQI4IKy5VvH7 .icon-shape .label{text-align:center;}#mermaid-svg-1IWPJQI4IKy5VvH7 .node.clickable{cursor:pointer;}#mermaid-svg-1IWPJQI4IKy5VvH7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .arrowheadPath{fill:#333333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1IWPJQI4IKy5VvH7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1IWPJQI4IKy5VvH7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1IWPJQI4IKy5VvH7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster text{fill:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 .cluster span{color:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1IWPJQI4IKy5VvH7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1IWPJQI4IKy5VvH7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-1IWPJQI4IKy5VvH7 .icon-shape,#mermaid-svg-1IWPJQI4IKy5VvH7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1IWPJQI4IKy5VvH7 .icon-shape p,#mermaid-svg-1IWPJQI4IKy5VvH7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1IWPJQI4IKy5VvH7 .icon-shape .label rect,#mermaid-svg-1IWPJQI4IKy5VvH7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1IWPJQI4IKy5VvH7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1IWPJQI4IKy5VvH7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1IWPJQI4IKy5VvH7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
互斥条件
持有并等待
不可抢占
循环等待
四个条件同时满足?
形成死锁
不会形成完整死锁闭环
1.3 死锁检测工具
java
/**
* 使用jstack检测死锁
*/
public class DeadLockDetector {
/**
* 使用ThreadMXBean检测死锁
*/
public static void detectDeadLock() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 查找死锁线程
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null && deadlockedThreads.length > 0) {
System.out.println("检测到死锁!涉及的线程:");
for (long threadId : deadlockedThreads) {
ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
System.out.println("线程名称:" + threadInfo.getThreadName());
System.out.println("线程状态:" + threadInfo.getThreadState());
// 打印死锁的Monitor
LockInfo[] lockedMonitors = threadInfo.getLockedMonitors();
for (LockInfo monitor : lockedMonitors) {
System.out.println("持有的Monitor:" + monitor);
}
}
} else {
System.out.println("未检测到死锁");
}
}
/**
* 定时检测死锁
*/
public static void startMonitoring() {
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
() -> detectDeadLock(),
0, 10, TimeUnit.SECONDS
);
}
}
1.4 解决死锁的方法
java
/**
* 方法1:固定加锁顺序
*/
public class FixedLockOrder {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
// 始终按照对象的hashCode顺序加锁
public void method1() {
// 计算hashCode并排序
if (System.identityHashCode(lock1) < System.identityHashCode(lock2)) {
synchronized (lock1) {
synchronized (lock2) {
// 业务逻辑
}
}
} else {
synchronized (lock2) {
synchronized (lock1) {
// 业务逻辑
}
}
}
}
}
java
/**
* 方法2:使用tryLockwith超时
*/
public class TryLockSolution {
private final Lock lock1 = newReentrantLock();
private final Lock lock2 = newReentrantLock();
public void methodWithTimeout() {
while (true) {
// 尝试获取lock1
if (lock1.tryLock()) {
try {
// 尝试获取lock2
if (lock2.tryLock()) {
try {
// 业务逻辑
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
// 等待后重试
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
}
java
/**
* 方法3:减少锁粒度,使用更细粒度的锁
*/
public class ReduceLockScope {
// 拆分为多个独立的锁
private final Map<String, Object> cache1 = new ConcurrentHashMap<>();
private final Map<String, Object> cache2 = new ConcurrentHashMap<>();
private final Lock lock1 = newReentrantLock();
private final Lock lock2 = newReentrantLock();
}
二、竞态条件
2.1 什么是竞态条件
竞态条件是指程序的执行结果依赖于线程的执行顺序,多个线程对共享资源的访问顺序不确定。
线程 B 共享变量 count 线程 A 线程 B 共享变量 count 线程 A #mermaid-svg-gsT32vHbad9DOM2G{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gsT32vHbad9DOM2G .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gsT32vHbad9DOM2G .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gsT32vHbad9DOM2G .error-icon{fill:#552222;}#mermaid-svg-gsT32vHbad9DOM2G .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gsT32vHbad9DOM2G .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gsT32vHbad9DOM2G .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gsT32vHbad9DOM2G .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gsT32vHbad9DOM2G .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gsT32vHbad9DOM2G .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gsT32vHbad9DOM2G .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gsT32vHbad9DOM2G .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gsT32vHbad9DOM2G .marker.cross{stroke:#333333;}#mermaid-svg-gsT32vHbad9DOM2G svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gsT32vHbad9DOM2G p{margin:0;}#mermaid-svg-gsT32vHbad9DOM2G .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gsT32vHbad9DOM2G text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-gsT32vHbad9DOM2G .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gsT32vHbad9DOM2G .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-gsT32vHbad9DOM2G .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-gsT32vHbad9DOM2G .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-gsT32vHbad9DOM2G #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-gsT32vHbad9DOM2G .sequenceNumber{fill:white;}#mermaid-svg-gsT32vHbad9DOM2G #sequencenumber{fill:#333;}#mermaid-svg-gsT32vHbad9DOM2G #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-gsT32vHbad9DOM2G .messageText{fill:#333;stroke:none;}#mermaid-svg-gsT32vHbad9DOM2G .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gsT32vHbad9DOM2G .labelText,#mermaid-svg-gsT32vHbad9DOM2G .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-gsT32vHbad9DOM2G .loopText,#mermaid-svg-gsT32vHbad9DOM2G .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-gsT32vHbad9DOM2G .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gsT32vHbad9DOM2G .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-gsT32vHbad9DOM2G .noteText,#mermaid-svg-gsT32vHbad9DOM2G .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-gsT32vHbad9DOM2G .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gsT32vHbad9DOM2G .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gsT32vHbad9DOM2G .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gsT32vHbad9DOM2G .actorPopupMenu{position:absolute;}#mermaid-svg-gsT32vHbad9DOM2G .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-gsT32vHbad9DOM2G .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gsT32vHbad9DOM2G .actor-man circle,#mermaid-svg-gsT32vHbad9DOM2G line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-gsT32vHbad9DOM2G :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 预期结果是 2,实际可能是 1 读取 count = 0读取 count = 0写回 count = 1写回 count = 1
java
/**
* 竞态条件示例:计数器
*/
public class RaceConditionDemo implementsRunnable {
private int counter = 0;
// 问题:++counter不是原子操作
// 实际执行:读取counter -> 增加 -> 写入
// 多个线程可能读到相同的值
public void increment() {
counter++;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
}
public static void main(String[] args) throws InterruptedException {
RaceConditionDemo demo = newRaceConditionDemo();
Thread t1 = new Thread(demo);
Thread t2 = new Thread(demo);
t1.start();
t2.start();
t1.join();
t2.join();
// 期望:20000
// 实际:可能是任意值(小于20000)
System.out.println(demo.counter);
}
}
2.2 常见的竞态条件模式
java
/**
* 模式1:Check-Then-Act
*/
public class CheckThenAct {
privateMap<String, Object> cache = new ConcurrentHashMap<>();
// 问题:检查和使用之间可能被其他线程修改
publicObjectgetOrCreate(String key) {
Object value = cache.get(key); // Check
if (value == null) { // Then
value = createValue(key); // Act
cache.put(key, value);
}
return value;
}
// 解决方案:使用computeIfAbsent
publicObjectgetOrCreateFixed(String key) {
return cache.computeIfAbsent(key, this::createValue);
}
}
java
/**
* 模式2:Read-Modify-Write
*/
public class ReadModifyWrite {
private int value = 0;
// 问题:读取、修改、写入不是原子操作
public void increment() {
int temp = value; // Read
temp = temp + 1; // Modify
value = temp; // Write
}
// 解决方案:使用原子类
private AtomicInteger atomicValue = newAtomicInteger(0);
public void incrementFixed() {
atomicValue.incrementAndGet();
}
}
2.3 解决竞态条件
java
/**
* 解决方案1:使用synchronized
*/
public class SynchronizedSolution {
private int counter = 0;
publicsynchronizedvoidincrement() {
counter++;
}
publicsynchronizedintget() {
return counter;
}
}
java
/**
* 解决方案2:使用ReentrantLock
*/
public class LockSolution {
private int counter = 0;
private final Lock lock = newReentrantLock();
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
publicintget() {
lock.lock();
try {
return counter;
} finally {
lock.unlock();
}
}
}
java
/**
* 解决方案3:使用原子类
*/
public class AtomicSolution {
private AtomicInteger counter = newAtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}
publicintget() {
return counter.get();
}
}
三、内存可见性问题
3.1 什么是内存可见性
内存可见性是指一个线程对共享变量的修改,其他线程能够及时看到。
#mermaid-svg-wYTNsCoD2ndQNId5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wYTNsCoD2ndQNId5 .error-icon{fill:#552222;}#mermaid-svg-wYTNsCoD2ndQNId5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wYTNsCoD2ndQNId5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wYTNsCoD2ndQNId5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wYTNsCoD2ndQNId5 .marker.cross{stroke:#333333;}#mermaid-svg-wYTNsCoD2ndQNId5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wYTNsCoD2ndQNId5 p{margin:0;}#mermaid-svg-wYTNsCoD2ndQNId5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster-label text{fill:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster-label span{color:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster-label span p{background-color:transparent;}#mermaid-svg-wYTNsCoD2ndQNId5 .label text,#mermaid-svg-wYTNsCoD2ndQNId5 span{fill:#333;color:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 .node rect,#mermaid-svg-wYTNsCoD2ndQNId5 .node circle,#mermaid-svg-wYTNsCoD2ndQNId5 .node ellipse,#mermaid-svg-wYTNsCoD2ndQNId5 .node polygon,#mermaid-svg-wYTNsCoD2ndQNId5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wYTNsCoD2ndQNId5 .rough-node .label text,#mermaid-svg-wYTNsCoD2ndQNId5 .node .label text,#mermaid-svg-wYTNsCoD2ndQNId5 .image-shape .label,#mermaid-svg-wYTNsCoD2ndQNId5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-wYTNsCoD2ndQNId5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wYTNsCoD2ndQNId5 .rough-node .label,#mermaid-svg-wYTNsCoD2ndQNId5 .node .label,#mermaid-svg-wYTNsCoD2ndQNId5 .image-shape .label,#mermaid-svg-wYTNsCoD2ndQNId5 .icon-shape .label{text-align:center;}#mermaid-svg-wYTNsCoD2ndQNId5 .node.clickable{cursor:pointer;}#mermaid-svg-wYTNsCoD2ndQNId5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wYTNsCoD2ndQNId5 .arrowheadPath{fill:#333333;}#mermaid-svg-wYTNsCoD2ndQNId5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wYTNsCoD2ndQNId5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wYTNsCoD2ndQNId5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wYTNsCoD2ndQNId5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wYTNsCoD2ndQNId5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wYTNsCoD2ndQNId5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster text{fill:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 .cluster span{color:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wYTNsCoD2ndQNId5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wYTNsCoD2ndQNId5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-wYTNsCoD2ndQNId5 .icon-shape,#mermaid-svg-wYTNsCoD2ndQNId5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wYTNsCoD2ndQNId5 .icon-shape p,#mermaid-svg-wYTNsCoD2ndQNId5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wYTNsCoD2ndQNId5 .icon-shape .label rect,#mermaid-svg-wYTNsCoD2ndQNId5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wYTNsCoD2ndQNId5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wYTNsCoD2ndQNId5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wYTNsCoD2ndQNId5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程 B
线程 A
未及时刷新
未及时同步
工作内存 A
修改共享变量 flag=false
工作内存 B
循环读取 flag
主内存
共享变量 flag
volatile / synchronized / Lock
建立可见性保障
java
/**
* 内存可见性问题
*/
public class VisibilityDemo {
privateboolean flag = true;
private int counter = 0;
// 线程1:写入flag
public void writer() {
counter = 1; // 步骤1
flag = false; // 步骤2
}
// 线程2:读取flag
public void reader() {
while (flag) { // 步骤3
// 等待
}
System.out.println(counter); // 步骤4
}
// 问题:线程2可能永远看不到flag的最新值
// 原因:CPU缓存 vs 主内存
}
java
/**
* 解决方案1:使用volatile
*/
public class VolatileSolution {
private volatile boolean flag = true;
private volatile int counter = 0;
// volatile保证:
// 1. 写操作立即刷新到主内存
// 2. 读操作从主内存读取
// 3. 禁止指令重排序(内存屏障)
}
java
/**
* 解决方案2:使用synchronized
*/
public class SynchronizedVisibility {
privateboolean flag = true;
private int counter = 0;
publicsynchronizedvoidwriter() {
counter = 1;
flag = false;
}
publicsynchronizedvoidreader() {
while (!flag) {
// 等待
}
System.out.println(counter);
}
}
3.2 volatile 的深入理解
java
/**
* volatile的三重语义
*/
public class VolatileUnderstanding {
// 1. 可见性
// 每次读取volatile变量都会从主内存读取
// 每次写入volatile变量都会立即刷新到主内存
volatileboolean ready;
volatileint number;
// 2. 禁止指令重排序
// volatile写操作之前的操作不会被重排序到volatile写之后
// volatile读操作之后的操作不会被重排序到volatile读之前
// 示例:
// volatile写之前的操作 a=1; b=2;
// volatile写:flag=true;
// volatile读:if (flag) { System.out.println(b); }
// 保证输出2而不是0
// 3. 不保证原子性
// 下面操作不是原子的
volatileint counter = 0;
// counter++ 实际是:读取->修改->写入
// 多个线程执行会导致数据丢失
}
四、并发容器问题
4.1 ConcurrentHashMap 的注意事项
java
/**
* ConcurrentHashMap的并发问题
*/
public class ConcurrentHashMapPitfalls {
// 问题1:复合操作不是原子的
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 错误的复合操作
public void wrongCompoundOps() {
// 先检查再操作 - 不是原子
if (map.containsKey("key")) {
map.get("key"); // 可能已被其他线程删除
}
// 迭代过程中修改 - ConcurrentModificationException
for (String key : map.keySet()) {
// 其他线程可能修改map
}
}
// 正确的做法:使用原子方法
public void correctOps() {
// 使用computeIfAbsent
map.computeIfAbsent("key", k -> 1);
// 使用putIfAbsent
map.putIfAbsent("key", 1);
// 使用replace
map.replace("key", 1, 2);
// 使用批量操作
map.forEach(1, (k, v) -> System.out.println(k + ":" + v));
}
}
4.2 CopyOnWriteArrayList 的注意事项
java
/**
* CopyOnWriteArrayList的适用场景
*/
public class CopyOnWritePitfalls {
// 适用:读多写少的场景
private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 问题:迭代器弱一致性
public void iteratorIssue() {
list.add("a");
list.add("b");
Iterator<String> iterator = list.iterator();
list.add("c"); // 修改后,迭代器不会反映新元素
while (iterator.hasNext()) {
System.out.println(iterator.next());
// 输出:a, b(不包含c)
}
}
// 问题:迭代器不支持remove操作
public void removeIssue() {
list.add("a");
list.add("b");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove(); // 抛出UnsupportedOperationException
}
}
}
五、线程池问题
5.1 线程池配置不当
#mermaid-svg-1cXZK2vefuDbVfrg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1cXZK2vefuDbVfrg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1cXZK2vefuDbVfrg .error-icon{fill:#552222;}#mermaid-svg-1cXZK2vefuDbVfrg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1cXZK2vefuDbVfrg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1cXZK2vefuDbVfrg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1cXZK2vefuDbVfrg .marker.cross{stroke:#333333;}#mermaid-svg-1cXZK2vefuDbVfrg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1cXZK2vefuDbVfrg p{margin:0;}#mermaid-svg-1cXZK2vefuDbVfrg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1cXZK2vefuDbVfrg .cluster-label text{fill:#333;}#mermaid-svg-1cXZK2vefuDbVfrg .cluster-label span{color:#333;}#mermaid-svg-1cXZK2vefuDbVfrg .cluster-label span p{background-color:transparent;}#mermaid-svg-1cXZK2vefuDbVfrg .label text,#mermaid-svg-1cXZK2vefuDbVfrg span{fill:#333;color:#333;}#mermaid-svg-1cXZK2vefuDbVfrg .node rect,#mermaid-svg-1cXZK2vefuDbVfrg .node circle,#mermaid-svg-1cXZK2vefuDbVfrg .node ellipse,#mermaid-svg-1cXZK2vefuDbVfrg .node polygon,#mermaid-svg-1cXZK2vefuDbVfrg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1cXZK2vefuDbVfrg .rough-node .label text,#mermaid-svg-1cXZK2vefuDbVfrg .node .label text,#mermaid-svg-1cXZK2vefuDbVfrg .image-shape .label,#mermaid-svg-1cXZK2vefuDbVfrg .icon-shape .label{text-anchor:middle;}#mermaid-svg-1cXZK2vefuDbVfrg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1cXZK2vefuDbVfrg .rough-node .label,#mermaid-svg-1cXZK2vefuDbVfrg .node .label,#mermaid-svg-1cXZK2vefuDbVfrg .image-shape .label,#mermaid-svg-1cXZK2vefuDbVfrg .icon-shape .label{text-align:center;}#mermaid-svg-1cXZK2vefuDbVfrg .node.clickable{cursor:pointer;}#mermaid-svg-1cXZK2vefuDbVfrg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1cXZK2vefuDbVfrg .arrowheadPath{fill:#333333;}#mermaid-svg-1cXZK2vefuDbVfrg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1cXZK2vefuDbVfrg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1cXZK2vefuDbVfrg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1cXZK2vefuDbVfrg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1cXZK2vefuDbVfrg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1cXZK2vefuDbVfrg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1cXZK2vefuDbVfrg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1cXZK2vefuDbVfrg .cluster text{fill:#333;}#mermaid-svg-1cXZK2vefuDbVfrg .cluster span{color:#333;}#mermaid-svg-1cXZK2vefuDbVfrg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1cXZK2vefuDbVfrg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1cXZK2vefuDbVfrg rect.text{fill:none;stroke-width:0;}#mermaid-svg-1cXZK2vefuDbVfrg .icon-shape,#mermaid-svg-1cXZK2vefuDbVfrg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1cXZK2vefuDbVfrg .icon-shape p,#mermaid-svg-1cXZK2vefuDbVfrg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1cXZK2vefuDbVfrg .icon-shape .label rect,#mermaid-svg-1cXZK2vefuDbVfrg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1cXZK2vefuDbVfrg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1cXZK2vefuDbVfrg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1cXZK2vefuDbVfrg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
否
是
是
否
提交任务
核心线程是否空闲?
核心线程执行
工作队列是否已满?
进入阻塞队列
是否可创建非核心线程?
创建临时线程执行
触发拒绝策略
线程池消费队列任务
java
/**
* 线程池问题
*/
public class ThreadPoolPitfalls {
// 问题1:使用 Executors 的不恰当方法
// FixedThreadPool和SingleThreadPool使用无界队列,可能导致OOM
ExecutorService badPool1 = Executors.newFixedThreadPool(100); // 队列 Integer.MAX_VALUE
ExecutorService badPool2 = Executors.newSingleThreadExecutor();
// 正确做法:使用ThreadPoolExecutor并指定队列大小
ExecutorService goodPool = new ThreadPoolExecutor(
10, 100,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000), // 有界队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 问题2:线程池拒绝策略不当
// AbortPolicy:直接抛异常
// DiscardPolicy:静默丢弃
// DiscardOldestPolicy:丢弃最老的任务
// CallerRunsPolicy:由调用线程执行
// 问题3:共享线程池导致阻塞
public void sharedPoolIssue() {
ExecutorService pool = Executors.newFixedThreadPool(10);
// 在线程池的任务中使用阻塞操作,可能导致死锁
pool.submit(() -> {
// 这是一个可能死锁的操作
try {
pool.submit(() -> {
// 子任务也在等待
}).get(); // 等待完成
} catch (Exception e) {}
});
}
}
5.2 线程泄漏
java
/**
* 线程泄漏问题
*/
public class ThreadLeakExample {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
private final ThreadLocal<String> threadLocal = new ThreadLocal<>();
// 问题1:ThreadLocal内存泄漏
public void threadLocalLeak() {
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
threadLocal.set(Thread.currentThread().getName());
// 忘记清理
// threadLocal.remove();
});
}
}
// 解决:使用完立即remove
public void threadLocalFixed() {
executor.submit(() -> {
try {
threadLocal.set(Thread.currentThread().getName());
// 业务逻辑
} finally {
threadLocal.remove(); // 关键
}
});
}
}
六、异步编程问题
6.1 Future 的坑
异步任务 线程池 主线程 异步任务 线程池 主线程 #mermaid-svg-d1FtuuryPgfZ1vHx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-d1FtuuryPgfZ1vHx .error-icon{fill:#552222;}#mermaid-svg-d1FtuuryPgfZ1vHx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-d1FtuuryPgfZ1vHx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-d1FtuuryPgfZ1vHx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-d1FtuuryPgfZ1vHx .marker.cross{stroke:#333333;}#mermaid-svg-d1FtuuryPgfZ1vHx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-d1FtuuryPgfZ1vHx p{margin:0;}#mermaid-svg-d1FtuuryPgfZ1vHx .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-d1FtuuryPgfZ1vHx text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-d1FtuuryPgfZ1vHx .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-d1FtuuryPgfZ1vHx .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-d1FtuuryPgfZ1vHx #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-d1FtuuryPgfZ1vHx .sequenceNumber{fill:white;}#mermaid-svg-d1FtuuryPgfZ1vHx #sequencenumber{fill:#333;}#mermaid-svg-d1FtuuryPgfZ1vHx #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-d1FtuuryPgfZ1vHx .messageText{fill:#333;stroke:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-d1FtuuryPgfZ1vHx .labelText,#mermaid-svg-d1FtuuryPgfZ1vHx .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .loopText,#mermaid-svg-d1FtuuryPgfZ1vHx .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-d1FtuuryPgfZ1vHx .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-d1FtuuryPgfZ1vHx .noteText,#mermaid-svg-d1FtuuryPgfZ1vHx .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-d1FtuuryPgfZ1vHx .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-d1FtuuryPgfZ1vHx .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-d1FtuuryPgfZ1vHx .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-d1FtuuryPgfZ1vHx .actorPopupMenu{position:absolute;}#mermaid-svg-d1FtuuryPgfZ1vHx .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-d1FtuuryPgfZ1vHx .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-d1FtuuryPgfZ1vHx .actor-man circle,#mermaid-svg-d1FtuuryPgfZ1vHx line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-d1FtuuryPgfZ1vHx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt任务执行慢或阻塞任务抛异常 submit(task)执行任务future.get()主线程被阻塞异常被封装get() 时才感知 ExecutionException
java
/**
* Future常见问题
*/
public class FuturePitfalls {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
// 问题1:get()阻塞导致线程阻塞
public void getBlocking() {
Future<String> future = executor.submit(() -> {
Thread.sleep(10000);
return "result";
});
// 阻塞等待,可能导致线程池耗尽
String result = future.get(); // 阻塞!
}
// 问题2:未正确处理异常
public void exceptionNotHandled() {
Future<String> future = executor.submit(() -> {
throw new RuntimeException("error");
});
// 如果不调用get(),异常会被吞噬
// future.get(); // 可以看到异常
}
// 正确做法1:使用回调
public void callbackApproach() {
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> "result", executor)
.thenApply(result -> result.toUpperCase())
.exceptionally(ex -> {
System.err.println("Error: " + ex.getMessage());
return "default";
});
}
// 正确做法2:使用超时
public void timeoutApproach() {
Future<String> future = executor.submit(() -> {
Thread.sleep(10000);
return "result";
});
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
} catch (Exception e) {}
}
}
6.2 异步调用链问题
java
/**
* 异步调用链问题
*/
public class AsyncChainPitfalls {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
// 问题1:线程上下文丢失
public void contextLoss() {
ThreadLocal<String> context = new ThreadLocal<>();
context.set("main-context");
executor.submit(() -> {
// 子线程中无法获取主线程的context
System.out.println(context.get()); // null
});
}
// 问题2:异常传播丢失
public void exceptionLoss() {
executor.submit(() -> {
throw new RuntimeException("error in async");
});
// 异常未处理,线程终止但不抛向主线程
}
// 正确做法:使用InheritableThreadLocal或上下文传递
public void contextPropagation() {
ExecutorService contextualExecutor =
Contexts.wrap(Executors.newFixedThreadPool(10));
// 或者使用阿里开源的TransmittableThreadLocal
}
}
七、性能问题
7.1 锁竞争优化
java
/**
* 锁竞争优化策略
*/
public class LockContentionOptimization {
// 策略1:减少锁持有时间
public void reduceLockTime() {
// 错误:长时间持有锁
synchronized (this) {
// 业务处理
// ...
// 数据库操作(耗时)
// ...
// 网络调用(耗时)
}
// 正确:快速释放锁
Object data;
synchronized (this) {
data = this.data; // 只获取数据
}
// 耗时操作在锁外进行
process(data);
}
// 策略2:减小锁粒度
private final Map<String, Object> map1 = new ConcurrentHashMap<>();
private final Map<String, Object> map2 = new ConcurrentHashMap<>();
// 替代单一全局锁
// 将数据分片到多个map
}
7.2 伪共享问题
java
/**
* 伪共享问题
*/
public class FalseSharingProblem {
// 问题:LongAdder的分段设计解决伪共享
// 每个Segment有独立的计数器
// 避免多个线程竞争同一缓存行
// 解决方案:缓存行填充
public static class PaddedLong {
private long p1, p2, p3, p4, p5, p6, p7;
public volatile long value;
private long p8, p9, p10, p11, p12, p13, p14;
}
// Java 8+ 可以使用 @Contended 注解
// @Contended
// public class ContendedLong {
// public volatile long value;
// }
}
八、调试与排查技巧
8.1 常用诊断工具
#mermaid-svg-rUkUIIydjY2tTs2c{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rUkUIIydjY2tTs2c .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rUkUIIydjY2tTs2c .error-icon{fill:#552222;}#mermaid-svg-rUkUIIydjY2tTs2c .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rUkUIIydjY2tTs2c .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rUkUIIydjY2tTs2c .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rUkUIIydjY2tTs2c .marker.cross{stroke:#333333;}#mermaid-svg-rUkUIIydjY2tTs2c svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rUkUIIydjY2tTs2c p{margin:0;}#mermaid-svg-rUkUIIydjY2tTs2c .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rUkUIIydjY2tTs2c .cluster-label text{fill:#333;}#mermaid-svg-rUkUIIydjY2tTs2c .cluster-label span{color:#333;}#mermaid-svg-rUkUIIydjY2tTs2c .cluster-label span p{background-color:transparent;}#mermaid-svg-rUkUIIydjY2tTs2c .label text,#mermaid-svg-rUkUIIydjY2tTs2c span{fill:#333;color:#333;}#mermaid-svg-rUkUIIydjY2tTs2c .node rect,#mermaid-svg-rUkUIIydjY2tTs2c .node circle,#mermaid-svg-rUkUIIydjY2tTs2c .node ellipse,#mermaid-svg-rUkUIIydjY2tTs2c .node polygon,#mermaid-svg-rUkUIIydjY2tTs2c .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rUkUIIydjY2tTs2c .rough-node .label text,#mermaid-svg-rUkUIIydjY2tTs2c .node .label text,#mermaid-svg-rUkUIIydjY2tTs2c .image-shape .label,#mermaid-svg-rUkUIIydjY2tTs2c .icon-shape .label{text-anchor:middle;}#mermaid-svg-rUkUIIydjY2tTs2c .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rUkUIIydjY2tTs2c .rough-node .label,#mermaid-svg-rUkUIIydjY2tTs2c .node .label,#mermaid-svg-rUkUIIydjY2tTs2c .image-shape .label,#mermaid-svg-rUkUIIydjY2tTs2c .icon-shape .label{text-align:center;}#mermaid-svg-rUkUIIydjY2tTs2c .node.clickable{cursor:pointer;}#mermaid-svg-rUkUIIydjY2tTs2c .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rUkUIIydjY2tTs2c .arrowheadPath{fill:#333333;}#mermaid-svg-rUkUIIydjY2tTs2c .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rUkUIIydjY2tTs2c .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rUkUIIydjY2tTs2c .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rUkUIIydjY2tTs2c .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rUkUIIydjY2tTs2c .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rUkUIIydjY2tTs2c .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rUkUIIydjY2tTs2c .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rUkUIIydjY2tTs2c .cluster text{fill:#333;}#mermaid-svg-rUkUIIydjY2tTs2c .cluster span{color:#333;}#mermaid-svg-rUkUIIydjY2tTs2c div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rUkUIIydjY2tTs2c .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rUkUIIydjY2tTs2c rect.text{fill:none;stroke-width:0;}#mermaid-svg-rUkUIIydjY2tTs2c .icon-shape,#mermaid-svg-rUkUIIydjY2tTs2c .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rUkUIIydjY2tTs2c .icon-shape p,#mermaid-svg-rUkUIIydjY2tTs2c .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rUkUIIydjY2tTs2c .icon-shape .label rect,#mermaid-svg-rUkUIIydjY2tTs2c .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rUkUIIydjY2tTs2c .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rUkUIIydjY2tTs2c .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rUkUIIydjY2tTs2c :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程卡住
CPU 高
数据不一致
线程池堆积
发现并发异常
卡死 / 数据错乱 / CPU 飙高
问题类型判断
jstack / Arthas thread
top + jstack / async-profiler
代码审查共享变量与锁
查看队列长度 / 活跃线程 / 拒绝策略
定位阻塞点或死锁链
定位热点方法与锁竞争
检查原子性 / 可见性 / 有序性
调整线程池参数或降级策略
修复并压测验证
java
/**
* 并发问题诊断工具
*/
public class ConcurrencyDiagnostics {
// 1. jstack - 打印线程堆栈
// jstack <pid>
// 2. jconsole - 监控线程状态
// 3. VisualVM - 可视化分析
// 4. Async-profiler - 性能分析
// 5. 使用Arthas
// thread - 查看线程堆栈
// thread -b - 查找阻塞的线程
// thread --state WAITING - 查看等待状态的线程
}
8.2 代码审查要点
java
/**
* 并发代码审查清单
*/
public class ConcurrencyChecklist {
// 1. 共享可变状态
// - 是否有多个线程访问共享变量?
// - 是否使用了正确的同步机制?
// 2. 对象逸出
// - 是否在构造过程中逸出了this引用?
// - 是否有内部类隐式持有外部类引用?
// 3. 线程安全委托
// - 是否正确使用了线程安全类?
// - 是否误用了非线程安全类?
// 4. 死锁风险
// - 多个锁的获取顺序是否一致?
// - 是否有tryLock超时机制?
// 5. 资源管理
// - 线程池是否正确关闭?
// - ThreadLocal是否正确清理?
}
九、面试高频问题
#mermaid-svg-dWHEu5W4TebYyLMM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dWHEu5W4TebYyLMM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dWHEu5W4TebYyLMM .error-icon{fill:#552222;}#mermaid-svg-dWHEu5W4TebYyLMM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dWHEu5W4TebYyLMM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dWHEu5W4TebYyLMM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dWHEu5W4TebYyLMM .marker.cross{stroke:#333333;}#mermaid-svg-dWHEu5W4TebYyLMM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dWHEu5W4TebYyLMM p{margin:0;}#mermaid-svg-dWHEu5W4TebYyLMM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dWHEu5W4TebYyLMM .cluster-label text{fill:#333;}#mermaid-svg-dWHEu5W4TebYyLMM .cluster-label span{color:#333;}#mermaid-svg-dWHEu5W4TebYyLMM .cluster-label span p{background-color:transparent;}#mermaid-svg-dWHEu5W4TebYyLMM .label text,#mermaid-svg-dWHEu5W4TebYyLMM span{fill:#333;color:#333;}#mermaid-svg-dWHEu5W4TebYyLMM .node rect,#mermaid-svg-dWHEu5W4TebYyLMM .node circle,#mermaid-svg-dWHEu5W4TebYyLMM .node ellipse,#mermaid-svg-dWHEu5W4TebYyLMM .node polygon,#mermaid-svg-dWHEu5W4TebYyLMM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dWHEu5W4TebYyLMM .rough-node .label text,#mermaid-svg-dWHEu5W4TebYyLMM .node .label text,#mermaid-svg-dWHEu5W4TebYyLMM .image-shape .label,#mermaid-svg-dWHEu5W4TebYyLMM .icon-shape .label{text-anchor:middle;}#mermaid-svg-dWHEu5W4TebYyLMM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dWHEu5W4TebYyLMM .rough-node .label,#mermaid-svg-dWHEu5W4TebYyLMM .node .label,#mermaid-svg-dWHEu5W4TebYyLMM .image-shape .label,#mermaid-svg-dWHEu5W4TebYyLMM .icon-shape .label{text-align:center;}#mermaid-svg-dWHEu5W4TebYyLMM .node.clickable{cursor:pointer;}#mermaid-svg-dWHEu5W4TebYyLMM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dWHEu5W4TebYyLMM .arrowheadPath{fill:#333333;}#mermaid-svg-dWHEu5W4TebYyLMM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dWHEu5W4TebYyLMM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dWHEu5W4TebYyLMM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dWHEu5W4TebYyLMM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dWHEu5W4TebYyLMM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dWHEu5W4TebYyLMM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dWHEu5W4TebYyLMM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dWHEu5W4TebYyLMM .cluster text{fill:#333;}#mermaid-svg-dWHEu5W4TebYyLMM .cluster span{color:#333;}#mermaid-svg-dWHEu5W4TebYyLMM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dWHEu5W4TebYyLMM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dWHEu5W4TebYyLMM rect.text{fill:none;stroke-width:0;}#mermaid-svg-dWHEu5W4TebYyLMM .icon-shape,#mermaid-svg-dWHEu5W4TebYyLMM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dWHEu5W4TebYyLMM .icon-shape p,#mermaid-svg-dWHEu5W4TebYyLMM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dWHEu5W4TebYyLMM .icon-shape .label rect,#mermaid-svg-dWHEu5W4TebYyLMM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dWHEu5W4TebYyLMM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dWHEu5W4TebYyLMM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dWHEu5W4TebYyLMM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
是
否
线程安全类设计
识别共享可变状态
定义不变约束
状态是否需要并发修改?
优先不可变对象 / 线程封闭
操作是否简单计数或 CAS 可表达?
Atomic / LongAdder / 并发容器
synchronized / Lock / ReadWriteLock
控制锁粒度与加锁顺序
补充可见性与异常处理
文档说明线程安全策略
Q1: 如何排查死锁?
- 使用
jstack查看线程堆栈,找到互相等待的线程 - 使用
ThreadMXBean的findDeadlockedThreads方法 - 查看代码中的加锁顺序
- 使用
Arthas的thread -b命令
Q2: volatile 和 synchronized 的区别?
| 特性 | volatile |
synchronized |
|---|---|---|
| 作用 | 可见性、有序性 | 可见性、有序性、原子性 |
| 性能 | 更好 | 较差 |
| 使用场景 | 标记位、状态位 | 复杂业务逻辑 |
Q3: ConcurrentHashMap 为什么高效?
- 内部使用分段锁,减少锁竞争
- 使用 CAS 操作,减少阻塞
- 读操作无锁(volatile)
- 键值对不允许为 null
Q4: 什么是伪共享?
CPU 缓存行是 64 字节,当多个变量共享同一缓存行,一个线程修改会导致其他线程的缓存行失效,即使它们访问的是不同变量。
Q5: 如何设计线程安全的类?
- 识别共享可变状态
- 确定状态变量的不变约束
- 设计对象状态修改的并发策略
- 使用适当的同步机制
- 编写文档说明线程安全性
并发 Bug 往往在生产环境中才会暴露,养成良好的并发编程习惯,使用正确的同步机制,是避免并发问题的关键。