共计 1375 个字符,预计需要花费 4 分钟才能阅读完成。
核心概念
线程安全是指当多个线程同时访问某个对象或方法时,系统仍能保持正确的行为。在高并发场景下,线程安全问题尤为突出,可能导致数据不一致、系统崩溃等严重后果。

- 为什么重要 :现代应用普遍需要处理高并发请求,线程安全是保证系统稳定性的基础。
- 典型场景 :电商秒杀、金融交易、实时数据处理等。
痛点分析
1. 数据竞争
当多个线程同时读写共享变量时,由于操作的非原子性,可能导致数据不一致。例如:
// 非线程安全的计数器
class Counter {
private int count = 0;
public void increment() { count++;}
}
2. 死锁
多个线程互相持有对方需要的锁,导致无限等待。常见于嵌套锁场景。
3. 内存可见性
由于 CPU 缓存机制,线程可能读取到过期的共享变量值。
技术方案
1. ReentrantLock
可重入锁,提供比 synchronized 更灵活的锁定机制。
优点:
– 支持公平锁
– 可中断的锁获取
– 尝试获取锁(tryLock)
缺点:
– 需要手动释放锁
– 代码复杂度略高
2. Atomic 类
基于 CAS(Compare-And-Swap)实现的无锁线程安全类。
适用场景:
– 简单的计数器
– 状态标志位
3. ConcurrentHashMap
线程安全的哈希表实现,采用分段锁技术。
性能特点:
– 读操作几乎不需要锁
– 写操作锁粒度小
代码示例
ReentrantLock 使用示例
import java.util.concurrent.locks.ReentrantLock;
class SafeCounter {private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {lock.lock();
try {count++;} finally {lock.unlock(); // 确保锁释放
}
}
}
AtomicInteger 使用示例
import java.util.concurrent.atomic.AtomicInteger;
class AtomicCounter {private AtomicInteger count = new AtomicInteger(0);
public void increment() {count.incrementAndGet(); // 原子操作
}
}
性能 / 安全性考量
- ReentrantLock vs synchronized
- ReentrantLock 在高竞争场景下性能更好
-
synchronized 在 JDK6+ 优化后差距缩小
-
Atomic 类
- 无锁设计,吞吐量高
-
适合简单操作,复杂操作仍需锁
-
锁粒度
- 细粒度锁提高并发度
- 但会增加死锁风险
避坑指南
- 避免锁粒度过大
- 只锁定必要的代码块
-
不要锁整个方法
-
锁顺序
-
统一获取锁的顺序,避免死锁
-
线程池配置
- 根据任务类型选择合适线程池
-
监控线程池状态
-
资源清理
- 确保在 finally 块中释放锁
- 关闭线程池
总结与思考
线程安全是高并发系统设计的核心问题之一。通过合理选择并发工具,可以构建既安全又高效的系统。建议在实际项目中:
- 根据场景选择最简单有效的方案
- 进行充分的压力测试
- 监控运行时状态
你可以思考:
– 当前项目中有哪些潜在的线程安全问题?
– 如何评估不同方案的性能影响?
– 是否可以考虑无锁设计?
进一步学习建议:
– Java 并发编程实战(书籍)
– JUC 包源码分析
– 并发模式与性能调优
