上篇回顾1.7-01 把 JVM 内存模型、GC 算法、收集器演进、排查工具链一次讲透。本篇进入并发编程——这是 Java 高阶最硬核的部分也是线上事故的高发区。并发 bug 的特点是「本地测不出来、上线偶发出现、复现极难」根因往往是对 JMM、锁机制、线程池理解不到位。一、开篇一次诡异的线上死锁某团队线上服务每隔几小时就卡死重启后恢复。日志没有异常线程全部正常。运维用jstackdump 线程栈一看transfer-thread-1 prio5 BLOCKED - waiting to lock 0x000000076b4a0c80 - locked 0x000000076b4a0c90 transfer-thread-2 prio5 BLOCKED - waiting to lock 0x000000076b4a0c90 - locked 0x000000076b4a0c80经典死锁线程 1 持有锁 A 等锁 B线程 2 持有锁 B 等锁 A。根因是两个方法以相反顺序加锁——转账方法 A 先锁 from 再锁 to方法 B 先锁 to 再锁 from。修复方案统一锁顺序按 accountId 排序小的先锁。但这个 bug 在本地跑了 10 万次都没出现——并发问题的可怕在于概率性。本篇把 JMM、锁机制、线程池三大基石讲透让你写出不翻车的并发代码。二、JMMJava 内存模型2.1 为什么需要 JMMCPU 有多级缓存每个核心看到的变量值可能不一致。Java 为了跨平台统一行为定义了 JMM——规定线程何时能看到其他线程的修改。线程 1 线程 2 ↓ ↓ 工作内存 工作内存 ↕ ↕ └───── 主内存 ───────┘JMM 规定线程不能直接操作主内存必须先读到工作内存修改后写回。2.2 三大特性特性含义保证手段原子性操作不可分割synchronized / Lock / AtomicInteger可见性修改后其他线程立即可见volatile / synchronized / final有序性防止指令重排volatile / happens-before2.3 volatile 的语义边界volatile 做两件事可见性写后立刻刷主内存读前从主内存刷新2禁止指令重排插入内存屏障volatile不保证原子性。i即使 i 是 volatile 也不是线程安全的——i是「读加写」三步中间可能被打断。// volatile 的正确用法状态标志privatevolatilebooleanrunningtrue;publicvoidstop(){runningfalse;}publicvoidrun(){while(running){// 工作循环}}2.4 happens-before 规则happens-before 是 JMM 的核心——如果 A happens-before B那么 A 的操作对 B 可见。规则说明程序顺序同一线程内前操作 happens-before 后操作锁规则unlock happens-before 后续 lockvolatile 规则volatile 写 happens-before 后续 volatile 读线程启动start() happens-before 线程内任意操作线程终止线程内操作 happens-before 其他线程检测到终止传递性A→B 且 B→C 则 A→C三、synchronized 锁升级全过程JDK 6 后 synchronized 不再是「重量级锁」一棍子打死而是根据竞争情况自动升级。无锁 → 偏向锁 → 轻量级锁 → 重量级锁3.1 偏向锁第一个线程访问时对象头记录该线程 ID。下次该线程进入不需要 CAS 操作直接进入。适合单线程反复进入同步块的场景。3.2 轻量级锁第二个线程来竞争时偏向锁撤销升级为轻量级锁。用 CAS 操作把对象头指向线程栈中的锁记录。适合交替执行、无真实竞争的场景。3.3 重量级锁CAS 自旋超过阈值默认 10 次仍没拿到锁升级为重量级锁——进入 monitor线程挂起等待。适合竞争激烈的场景。3.4 锁升级不可逆一旦升级到重量级锁就不会降级。所以不要在低竞争场景用 synchronized 反复触发升级。3.5 synchronized vs ReentrantLock维度synchronizedReentrantLock实现JVM 内置java.util.concurrent 类锁释放自动手动 unlock必须 finally可中断不可lockInterruptibly()超时不可tryLock(timeout)公平锁非公平可配公平/非公平条件变量1 个wait/notify多个 Condition推荐简单场景用 synchronized语法简洁、不会忘记 unlock复杂场景超时、中断、多条件用 ReentrantLock。四、AQSJUC 的核心框架AbstractQueuedSynchronizer 是 ReentrantLock、CountDownLatch、Semaphore、CyclicBarrier 的底层框架。4.1 核心思想1. state 变量表示同步状态volatile int 2. CLH 队列管理等待线程 3. 模板方法模式子类实现 tryAcquire/tryRelease4.2 CLH 队列head → [线程1] ⇄ [线程2] ⇄ [线程3] ← tail ↑ 已获取锁 ↑ 自旋等待 ↑ 自旋等待等待线程在队列里自旋轻量级锁阶段或挂起重量级锁阶段前驱节点释放后唤醒后继。4.3 ReentrantLock 的 tryAcquire// 简化版finalbooleannonfairTryAcquire(intacquires){finalThreadcurrentThread.currentThread();intcgetState();if(c0){// 无锁状态CAS 抢锁if(compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}elseif(currentgetExclusiveOwnerThread()){// 重入state 加 1setState(cacquires);returntrue;}returnfalse;}五、CAS 与 ABA 问题5.1 CAS 原理Compare And Swap比较当前值是否等于预期值相等则更新为新值。是乐观锁的核心。AtomicIntegerainewAtomicInteger(0);ai.compareAndSet(0,1);// 预期0更新为1 → trueai.compareAndSet(0,2);// 预期0但已是1 → false5.2 ABA 问题线程1 读到值 A 线程2 把 A 改成 B又改回 A 线程1 CAS(A→C) 成功值虽然还是 A但中间已经被改过。对纯数值无影响对引用类型可能有问题对象字段被改了但引用没变。5.3 解决方案AtomicStampedReference给值加版本号CAS 时同时比较值和版本号。AtomicStampedReferenceIntegerrefnewAtomicStampedReference(100,0);// 初始值100版本0int[]stampnewint[1];Integervalref.get(stamp);// val100, stamp[0]0ref.compareAndSet(100,200,0,1);// 预期值100版本0 → 更新为200版本1六、线程池为什么阿里禁止 Executors6.1 Executors 的隐患// 阿里规约禁止这两种Executors.newFixedThreadPool(10);// 队列 LinkedBlockingQueue 无上限 → OOMExecutors.newCachedThreadPool();// 线程数 Integer.MAX_VALUE → OOMnewFixedThreadPool 的队列是LinkedBlockingQueue无界任务堆积导致 OOM。newCachedThreadPool 的最大线程数是Integer.MAX_VALUE创建过多线程导致 OOM。6.2 正确做法手动配置 ThreadPoolExecutorThreadPoolExecutorexecutornewThreadPoolExecutor(corePoolSize,// 核心线程数maxPoolSize,// 最大线程数keepAliveTime,// 空闲存活时间TimeUnit.SECONDS,newArrayBlockingQueue(1000),// 有界队列newThreadFactoryBuilder().setNameFormat(biz-pool-%d).build(),// 命名便于排查newThreadPoolExecutor.CallerRunsPolicy()// 拒绝策略);6.3 七参数详解参数说明corePoolSize常驻线程数maxPoolSize队列满后扩到的最大线程数keepAliveTime非核心线程空闲存活时间unit时间单位workQueue任务队列threadFactory线程工厂命名很重要handler拒绝策略6.4 线程数设置公式CPU 密集型计算为主线程数 CPU 核数 1IO 密集型网络/DB/文件为主线程数 CPU 核数 * (1 IO等待时间/CPU时间)经验值IO 密集型通常 2~10 倍 CPU 核数。具体靠压测调。6.5 四种拒绝策略策略行为适用场景AbortPolicy抛 RejectedExecutionException默认要求严格CallerRunsPolicy由提交线程执行不丢任务、降级DiscardPolicy静默丢弃可容忍丢任务DiscardOldestPolicy丢最早未处理任务最新优先生产推荐CallerRunsPolicy——不丢任务用提交线程做背压。七、CompletableFuture现代异步编程CompletableFutureOrderfutureCompletableFuture.supplyAsync(()-userService.getById(userId),executor).thenApply(user-{OrderordernewOrder(user);returnorder;}).thenCombine(CompletableFuture.supplyAsync(()-couponService.get(userId),executor),(order,coupon)-{order.setCoupon(coupon);returnorder;}).exceptionally(ex-{log.error(创建订单失败,ex);returnOrder.failed(ex.getMessage());});Orderorderfuture.get(3,TimeUnit.SECONDS);优势链式编排、超时控制、异常处理、多任务组合。比 Future 灵活得多。八、小结表模块关键点易踩坑JMM可见性/原子性/有序性volatile 不保证原子性synchronized锁升级不可逆低竞争反复触发升级AQSstate CLH 队列自旋过多浪费 CPUCAS乐观锁ABA 问题线程池手动配七参数Executors 无界队列 OOMCompletableFuture异步编排必须传自定义线程池
企业数字化 ERP 产品动态
相关推荐
夸克自启动原理与跨平台精准拦截方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:37:18
Vibe Coding:嵌入式开发者的物理世界直觉养成指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:37:18
基于STM32的智能计价电子秤设计与实现全解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:37:12
有经验的武进网站建设注意事项 武进建站避坑指南:从零搭建到流量变现的3个实战细节 自己不会代码想做网站,却总被各种“专业术语”劝退?在常州武进区,很多企业主想从零搭建一个能带来订单的官网,结果发现找外包公司报价从几千到几万不等,质量还参差不齐。… · 2026/9/27 3:23:14
跃动自贸港,绳彩大三亚!2026年海南跳绳公开赛圆满落幕 本报讯 9月26日,主题为“跃动自贸港,绳彩大三亚”的2026年海南跳绳公开赛在三亚极一篮球俱乐部圆满闭幕。赛事立足海南自贸港体育发展布局,深度落地赛事旅游融合发展模式,打造国际化、大众化、特色化的群众体育精品赛事。本次赛事… · 2026/9/27 3:23:02
告别反复下载安装包:Electron动态薄壳打造点刷新即秒级热更新实战 文章目录1. 传统桌面发版的痛感账本:改一行代码遭全套打包罪受1.1. 开发环境与依赖矩阵:为什么传统模式难以维系?1.1.1. 120MB 安装包背后的漫长构建与上传链路1.2. 用户的更新心理壁垒与高流失率1.2.1. 弹窗强行升级打断用户心流与流失痛点2… · 2026/9/27 3:23:02
Metapi 数据看板与余额管理完整指南:多站点余额、消费趋势、收入追踪一目了然 Metapi 数据看板与余额管理完整指南:多站点余额、消费趋势、收入追踪一目了然 【免费下载链接】metapi 把你在各处注册的 New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API 等站点, 汇聚成 一个 API Key、一个入口,自动… · 2026/9/27 3:22:56
Codex CLI告别付费账单:awesome-freellm-apis 免费LLM后端环境变量配置详解 Codex CLI告别付费账单:awesome-freellm-apis 免费LLM后端环境变量配置详解 【免费下载链接】awesome-freellm-apis 134 free LLM APIs & AI API keys from 40 providers. Google Gemini, NVIDIA NIM, Groq, OpenRouter & more. One-click setup for Claude… · 2026/9/27 3:22:56
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01