本文目录导读:

这是一份 Java并发安全流程规范,这份规范旨在帮助开发团队在设计、编码和审查阶段系统性地规避并发问题(如竞态条件、死锁、内存一致性错误),该规范涵盖了从“共享资源识别”到“线程协作”的完整流程。
核心原则
- 最小化共享:优先设计无共享(无状态Bean、ThreadLocal)或只读共享(
final、不可变对象)的架构。 - 封装可变性:可变状态必须通过明确的锁或原子变量访问。
- 文档先行:每个可能被多线程访问的类或方法,必须明确标注其线程安全策略。
并发安全流程规范
阶段 1:识别与建模
- 步骤 1:识别共享资源
- 检查:静态变量、实例域(特别是集合、缓存、计数器)、文件句柄、数据库连接池、HttpSession。
- 行动:在类头部注释中列出所有共享的可变状态。
- 步骤 2:选择并发策略
- 线程封闭(推荐优先考虑):栈封闭(局部变量)、
ThreadLocal。 - 只读共享:
final字段(不可变对象如String、Integer、自定义record/不可变类)。 - 线程安全对象:使用
ConcurrentHashMap、CopyOnWriteArrayList、AtomicInteger、LongAdder等。 - 同步策略:
synchronized(隐式锁)、ReentrantLock、ReadWriteLock、StampedLock。
- 线程封闭(推荐优先考虑):栈封闭(局部变量)、
- 步骤 3:定义可见性保证
- 必须使用
volatile或锁来确保写操作的可见性。 - 规则:如果变量被一个线程写入并被另一个线程读取,必须使用
happens-before机制。
- 必须使用
阶段 2:编码实现规范
规则 1:锁的使用
- 锁粒度:
- 避免在同步块中执行耗时操作(如I/O、RPC调用)。
- 对同一共享资源,应使用同一个锁对象。
- 边界:能锁方法尽量不锁类,能锁代码块尽量不锁方法。
- 锁顺序:若要获取多个锁,必须定义全局顺序,否则易死锁。
- 例子:固定先锁
A再锁B。
- 例子:固定先锁
- 锁降级/释放:
- 对于
Lock接口,必须在finally块中释放锁。
- 对于
- 饥饿与公平:默认
ReentrantLock为非公平锁,高竞争场景可考虑公平锁(性能代价较高)。
// 正确示例
Lock lock = new ReentrantLock();
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
规则 2:复合操作
- 对于“检查再运行”(Check-Then-Act)或“读取-修改-写入”复合操作,必须加锁或使用原子类。
- 错误示例:
if (!map.containsKey(key)) { // 检查 map.put(key, value); // 运行 -> 竞态条件! } - 正确方案:
- 使用
ConcurrentHashMap.putIfAbsent(key, value)。 - 使用
synchronized(map) { if(!map.containsKey(key)) map.put(key,value); }。
- 使用
规则 3:发布与逸出
- 禁止在构造函数中将
this引用发布给外部(如注册监听器、启动线程)。- 原因:对象尚未完全初始化,其他线程可能看到半构造状态。
- 正确:先完成构造,再单独调用
register()或start()。
规则 4:线程池
- 必须通过
ThreadPoolExecutor(或Executors工厂方法,但需理解其限制)管理线程,禁止手动new Thread()。 - 核心参数:根据 CPU 密集型 或 IO 密集型 合理设置
corePoolSize、maxPoolSize、workQueue和handler(拒绝策略)。 - 使用有界队列(如
ArrayBlockingQueue),防止任务堆积导致 OOM。
规则 5:停止线程
- 禁止使用
Thread.stop()、Thread.suspend()、Thread.resume()(已废弃,不安全)。 - 标准方式:使用中断信号
interrupt()或volatile boolean标志位。- 任务应定期检查
Thread.currentThread().isInterrupted()。
- 任务应定期检查
阶段 3:测试与验证
- 并发测试:
- 编写专门的并发测试用例(如使用
CountDownLatch模拟并发启动)。 - 进行高负载、长时间压测,观察死锁、活锁或数据不一致。
- 编写专门的并发测试用例(如使用
- 静态分析:
- 使用 FindBugs、SpotBugs 的
-Dfindbugs.failOnBugPattern=BIT_ATOMIC_READ_WRITE,DC_DOUBLECHECK等规则。 - 使用 Checkstyle 或 PMD 检查
synchronized滥用或锁顺序。
- 使用 FindBugs、SpotBugs 的
- 代码审查 Checklist:
- [ ] 共享变量是否用 volatile 或锁保护? (可见性)
- [ ] 是否有 Check-Then-Act 未加锁? (原子性)
- [ ] 是否在同步块中执行了耗时 I/O 操作?
- [ ] 多个锁是否按固定顺序获取? (死锁)
- [ ] 锁是否在 finally 块中释放?
- [ ] 线程池参数是否基于压测验证过?
- [ ] 是否存在 this 逸出?
关键技术选型建议
| 场景 | 推荐方案 | 备注 |
|---|---|---|
| 计数器/统计 | LongAdder / AtomicLong |
高并发下 LongAdder 性能优于 AtomicLong |
| 全局缓存 | ConcurrentHashMap + computeIfAbsent |
避免二次检查 |
| 有序或排他访问 | ReentrantLock |
支持超时、公平、条件变量 |
| 读多写少 | ReadWriteLock / StampedLock |
StampedLock 乐观读性能极高 |
| 生产者-消费者 | BlockingQueue (如 LinkedBlockingQueue) |
与线程池配合使用 |
| 避免锁的开销 | ThreadLocal / 不可变对象 |
设计上无竞态 |
| 分布式互斥 | 分布式锁 (如 Redis RedLock, ZooKeeper) | 非 JVM 内部,需额外中间件 |
规范检查清单(代码审查速查)
- 原子性:复合操作是否加锁或使用原子类?
- 可见性:共享标志位是否
volatile?synchronized块是否覆盖所有读和写? - 有序性:是否存在依赖重排序导致的问题?
final字段是否确保安全发布? - 死锁:获取多个锁的顺序是否一致? 是否在持有锁时调用外部方法?(警惕回调死锁)
- 资源泄漏:
Lock是否在finally中释放? 线程池是否在应用关闭时优雅停服?
附录:常见反模式
- Double-Checked Locking 错误实现:
- 问题:未使用
volatile,导致读取到未完全构造的对象。 - 修复:使用
volatile或static inner class(Initialization-on-demand holder idiom)。
- 问题:未使用
- String 作为锁:
- 问题:
String.intern()或常量池可能导致误锁不相关的代码。 - 修复:使用
new Object()或专用对象作为锁。
- 问题:
- 同步集合遍历修改:
- 问题:
ConcurrentModificationException。 - 修复:使用
CopyOnWriteArrayList或在同步块中使用迭代器的remove()方法。
- 问题:
“先写正确,再写高效”,在 Java 并发中,清晰的安全边界(如明确的同步策略)远比微小的性能优化重要,开发人员在提交代码前,应比照以上规范逐项自查。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播