共享变量未同步是导致计数器偏小、数据重复或丢失、列表乱序等现象的根源,需重点检查静态变量、被多线程共用的实例变量及跨线程传递的可变对象,并通过加锁验证和工具辅助定位竞争窗口。

直接看日志和结果异常——比如计数器总比预期少、数据库记录重复或丢失、列表内容乱序或缺失,基本就能锁定是共享变量未同步的问题。
观察典型现象
数据错乱不是随机出错,而是有规律的“偏小”或“重复”。比如:
- 1000 次并发 i++,最终值却只有 827 —— 说明递增被覆盖
- 爬虫多线程写入同一个 List,最后条目数远少于请求总数
- 库存扣减后出现负数,或同一商品被超卖
这些都不是网络或逻辑错误,而是多个线程同时读-改-写同一内存地址造成的竞争窗口。
定位共享变量位置
重点检查三类地方:
-
静态变量:如
private static int counter = 0;—— 所有线程共用一份 - 实例变量被多个线程共用:比如一个服务对象被注入到多个线程任务中,其成员字段就成了共享状态
- 跨线程传递的可变对象:如把 ArrayList 作为参数传给多个 Runnable,而不是每个线程新建副本
局部变量(方法内 new 的对象、基本类型参数)天然线程安全,不用查。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
验证是否真由未加锁引起
临时加锁跑一次对比测试:
- 对可疑代码块加
synchronized(this)或synchronized(SharedClass.class) - 或改用
AtomicInteger替换普通 int,ConcurrentHashMap替换HashMap - 如果加锁后结果稳定且符合预期,就确认是同步缺失问题
注意:不要只测单次,要压测 50+ 线程跑 1000 轮,才能暴露竞争条件。
用工具辅助抓现场
仅靠日志难复现,建议组合使用:
- jstack + 线程名筛选:查是否有大量线程卡在相同代码行(可能是锁争用,也可能是无锁竞争)
- JMC(Java Mission Control)或 VisualVM 的“线程”视图:观察线程状态频繁切换、CPU 占用高但吞吐低
- 添加断点并启用“Thread suspend on breakpoint”:在共享变量读写处设断点,手动触发多线程执行,观察变量值被谁改、何时改
真正的问题往往藏在“看起来没问题”的赋值语句里,比如 list.add(item) —— ArrayList 本身不支持并发,没锁就会丢数据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










