本文目录导读:

我来系统地整理Java线程安全的完整知识体系。
线程安全核心概念
1 什么是线程安全
当多个线程访问某个类时,这个类始终表现出正确的行为,就称这个类是线程安全的。
2 线程不安全的根本原因
// 根本原因:多线程操作共享数据
private int count = 0;
public void increment() {
count++; // 不是原子操作:读取-修改-写入
}
三个条件同时发生时必然出现线程安全问题:
- 多线程环境
- 共享资源
- 非原子操作
线程安全实现方式(6大策略)
1 同步机制(Synchronized)
// 1. 同步方法
public synchronized void safeMethod() {
// 线程安全操作
}
// 2. 同步代码块(推荐:粒度更细)
public void safeBlock() {
synchronized(this) {
// 需要同步的操作
}
}
// 3. 静态方法同步(类锁)
public static synchronized void staticSafeMethod() {
// 同步操作
}
// 4. 指定对象锁
private final Object lock = new Object();
public void customLock() {
synchronized(lock) {
// 同步操作
}
}
2 Lock锁机制
import java.util.concurrent.locks.*;
public class LockExample {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // 必须释放锁
}
}
// 尝试获取锁
public boolean tryIncrement() {
if (lock.tryLock()) {
try {
count++;
return true;
} finally {
lock.unlock();
}
}
return false;
}
// 读写锁
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private Map<String, String> cache = new HashMap<>();
public String get(String key) {
rwLock.readLock().lock();
try {
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(String key, String value) {
rwLock.writeLock().lock();
try {
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
3 Volatile关键字
public class VolatileExample {
// volatile保证可见性和禁止指令重排
private volatile boolean flag = false;
private volatile int count = 0;
public void writer() {
count = 10; // 普通写
flag = true; // volatile写,保证前面的写操作对其他线程可见
}
public void reader() {
if (flag) { // volatile读
System.out.println(count); // 一定能看到10
}
}
}
4 原子类(Atomic)
import java.util.concurrent.atomic.*;
public class AtomicExample {
private AtomicInteger count = new AtomicInteger(0);
private AtomicLong longValue = new AtomicLong(0L);
private AtomicBoolean flag = new AtomicBoolean(false);
private AtomicReference<String> ref = new AtomicReference<>("initial");
public void increment() {
count.incrementAndGet(); // 原子自增
count.addAndGet(10); // 原子增加
count.compareAndSet(5, 6); // CAS操作
}
// 复杂对象原子更新
private AtomicReference<User> userRef = new AtomicReference<>();
// 字段原子更新
private AtomicIntegerFieldUpdater<Counter> updater =
AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");
}
5 并发容器
import java.util.concurrent.*;
public class ConcurrentCollectionExample {
// 1. ConcurrentHashMap - 分段锁
private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
// 2. CopyOnWriteArrayList - 写时复制
private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 3. BlockingQueue - 阻塞队列
private BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);
// 4. ConcurrentLinkedQueue - 无锁队列
private ConcurrentLinkedQueue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
public void safeOperations() {
// ConcurrentHashMap原子操作
map.putIfAbsent("key", "value"); // 不存在才put
map.computeIfAbsent("key", k -> "new"); // 不存在才计算
map.replace("key", "old", "new"); // 替换操作
// BlockingQueue阻塞操作
try {
queue.put("item"); // 满时阻塞
String item = queue.take(); // 空时阻塞
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
6 ThreadLocal
public class ThreadLocalExample {
// 每个线程维护自己的变量副本
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0; // 初始值
}
};
// Java 8 简化写法
private static ThreadLocal<SimpleDateFormat> dateFormat =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
// 使用示例
public void process() {
Integer value = threadLocal.get(); // 获取当前线程的变量
threadLocal.set(value + 1); // 设置当前线程的变量
threadLocal.remove(); // 使用后清理(避免内存泄漏)
}
// 实际应用:数据库连接管理
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
@Override
protected Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
}
线程安全设计原则
1 不变性(Immutability)
// 不可变对象天然线程安全
public final class ImmutableObject {
private final int id;
private final String name;
private final List<String> tags; // 防御性拷贝
public ImmutableObject(int id, String name, List<String> tags) {
this.id = id;
this.name = name;
this.tags = Collections.unmodifiableList(new ArrayList<>(tags));
}
public int getId() { return id; }
public String getName() { return name; }
public List<String> getTags() {
return tags; // 返回不可修改的视图
}
}
2 线程封闭
// 栈封闭:变量在方法内部,不会被共享
public void stackConfined() {
int localVar = 0; // 每个线程有自己的栈帧
for (int i = 0; i < 100; i++) {
localVar++;
}
}
// ThreadLocal封闭:每个线程自己的副本
private static ThreadLocal<TransactionManager> txManager = new ThreadLocal<>();
3 实例封闭
public class InstanceConfinement {
private final Set<String> set = new HashSet<>(); // 私有成员
private final Object lock = new Object();
public void add(String item) {
synchronized(lock) { // 通过锁保护
set.add(item);
}
}
public boolean contains(String item) {
synchronized(lock) {
return set.contains(item);
}
}
}
线程安全的正确实践
1 类级别线程安全
public class ThreadSafeCounter {
private final AtomicInteger count = new AtomicInteger(0);
private volatile boolean initialized = false;
// 线程安全的初始化
public void init() {
if (!initialized) {
synchronized(this) {
if (!initialized) {
// 双重检查锁定
doInit();
initialized = true;
}
}
}
}
// 线程安全的方法
public int incrementAndGet() {
return count.incrementAndGet();
}
// 复合操作需要同步
public int getAndReset() {
// 保证获取和重置的原子性
synchronized(this) {
int current = count.get();
count.set(0);
return current;
}
}
private void doInit() {
// 初始化代码
}
}
2 发布对象的安全
public class SafePublication {
// 1. 安全发布方式
private static volatile Singleton instance; // volatile确保可见性
// 2. 通过工厂方法安全发布
public static Singleton getInstance() {
if (instance == null) {
synchronized(SafePublication.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
// 3. 通过静态初始化安全发布(推荐)
private static class LazyHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance2() {
return LazyHolder.INSTANCE;
}
}
性能优化建议
1 锁优化策略
public class LockOptimization {
// 1. 减少锁持有时间
public void process(List<String> items) {
// 只对必要部分加锁
String result = expensiveComputation(items.get(0));
synchronized(this) {
updateSharedState(result);
}
}
// 2. 减小锁粒度
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private Map<String, String> map1 = new HashMap<>();
private Map<String, String> map2 = new HashMap<>();
public void updateMap1(String key, String value) {
synchronized(lock1) {
map1.put(key, value);
}
}
public void updateMap2(String key, String value) {
synchronized(lock2) {
map2.put(key, value);
}
}
// 3. 锁分离(读写锁)
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
// 4. 锁粗化(避免频繁加解锁)
public void coarsenLock() {
synchronized(this) {
// 多个操作合并
doOperation1();
doOperation2();
doOperation3();
}
}
}
2 选择合适的工具
public class ToolSelection {
// 场景1: 计数器 → 使用AtomicInteger
private final AtomicInteger counter = new AtomicInteger(0);
// 场景2: 共享变量标志位 → 使用volatile
private volatile boolean running = true;
// 场景3: 复杂状态 → 使用Lock或synchronized
private final ReentrantLock lock = new ReentrantLock();
private int state1, state2, state3;
// 场景4: 缓存 → 使用ConcurrentHashMap
private final ConcurrentHashMap<String, CacheEntry> cache =
new ConcurrentHashMap<>();
// 场景5: 生产者消费者 → 使用BlockingQueue
private final BlockingQueue<Task> taskQueue =
new ArrayBlockingQueue<>(1000);
// 场景6: 每个线程独立数据 → 使用ThreadLocal
private final ThreadLocal<UserContext> userContext =
ThreadLocal.withInitial(UserContext::new);
}
常见线程安全问题排查
1 典型问题模式
// 问题1: 非原子检查后执行
public class CheckThenAct {
private Vector<String> vector = new Vector<>();
// 问题代码
public void wrongMethod(String item) {
if (!vector.contains(item)) { // 检查
vector.add(item); // 执行(可能被其他线程干扰)
}
}
// 正确代码
public synchronized void correctMethod(String item) {
if (!vector.contains(item)) {
vector.add(item);
}
}
}
// 问题2: 发布逸出
public class EscapeExample {
private final Map<String, String> map;
// 问题代码:this引用逸出
public EscapeExample() {
// 不应该在构造器中发布this
GlobalRegistry.register(this); // ❌
map = new HashMap<>();
}
// 正确做法:使用工厂方法
private EscapeExample(Map<String, String> map) {
this.map = map;
}
public static EscapeExample create() {
EscapeExample instance = new EscapeExample(new HashMap<>());
GlobalRegistry.register(instance); // ✅ 构造完成后注册
return instance;
}
}
// 问题3: 隐藏的迭代器
public class HiddenIterator {
private final Set<Integer> set = new HashSet<>();
// 问题代码:toString()隐藏了迭代
public String wrongToString() {
return set.toString(); // ❌ 内部迭代,如果在迭代中修改会抛异常
}
// 正确代码
public synchronized String correctToString() {
return set.toString();
}
}
2 调试工具
// 1. 线程转储分析(Jstack)
jstack <pid> > thread_dump.txt
// 2. JVM参数检测
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintConcurrentLocks
// 3. 代码检测
public class DeadlockDetector {
public static void detectDeadlock() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadBean.findDeadlockedThreads();
if (threadIds != null) {
System.out.println("Deadlock detected!");
for (long id : threadIds) {
ThreadInfo info = threadBean.getThreadInfo(id);
System.out.println("Thread: " + info.getThreadName());
}
}
}
}
最佳实践总结
1 线程安全等级
| 等级 | 描述 | 示例 |
|---|---|---|
| 不可变 | 对象创建后不能修改 | String, Integer |
| 绝对线程安全 | 任何环境都安全 | ConcurrentHashMap |
| 相对线程安全 | 单操作安全,复合操作需同步 | Vector, Hashtable |
| 线程兼容 | 通过外部同步实现安全 | ArrayList, HashMap |
| 线程对立 | 即使外部同步也不安全 | (极少见) |
2 选择策略决策树
是否需要共享数据?
├── 否 → 使用ThreadLocal或栈封闭
└── 是 → 数据是否可变?
├── 否 → 使用不可变对象
└── 是 → 是否需要原子性?
├── 否 → 使用volatile
└── 是 → 操作是否简单?
├── 是 → 使用Atomic类
└── 否 → 是否需要读多写少?
├── 是 → 使用ReadWriteLock
└── 否 → 使用synchronized或ReentrantLock
3 编码规范
/** * 线程安全检查清单: * * [ ] 所有共享变量是否被正确保护? * [ ] 复合操作是否原子化? * [ ] 是否存在竞态条件? * [ ] 是否存在可见性问题? * [ ] 是否存在线程封闭的需求? * [ ] 是否选择了合适的同步策略? * [ ] 是否存在死锁风险? * [ ] 锁的粒度是否合适? */
这种系统化的线程安全处理方式,能够帮助你在多线程编程中做出正确的决策,避免常见的并发问题。