一、血泪教训:那些让你头皮发麻的并发Bug现场
场景1:简单的计数器,不简单的灾难
// 你以为安全的计数器?
public class Counter {
private int count = 0;
public void increment() {
count++; // 致命!这不是原子操作
}
public int getCount() {
return count;
}
}
// 在多线程环境下,100个线程各执行1000次increment()
// 你期望的结果:100000
// 实际结果可能是:97843、99217...每次都不一样!
场景2:Spring单例Bean中的“陷阱”
@Service
public class OrderService {
// 单例Bean中的成员变量 - 线程安全大坑!
private Map<Long, Order> currentOrders = new HashMap<>();
public void processOrder(Long orderId) {
Order order = orderDao.findById(orderId);
currentOrders.put(orderId, order); // 多个线程并发操作同一个Map!
// ... 业务处理
currentOrders.remove(orderId);
}
}
场景3:SimpleDateFormat引发的午夜惊魂
// 全局共享的日期格式化器 - 经典错误
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String formatDate(Date date) {
return sdf.format(date); // 多线程下可能返回乱码或抛出异常!
}
// 真实案例:某银行系统在月末对账时出现日期错乱,损失惨重
二、深度剖析:为什么线程安全如此棘手?
根源分析
-
可见性问题:一个线程的修改,另一个线程看不见
-
原子性问题:看似一行代码,实际包含多个操作
-
有序性问题:编译器/处理器重排序导致的诡异现象
JMM(Java内存模型)真相
// 看似简单的代码,隐藏着内存可见性问题
public class VisibilityProblem {
private boolean flag = false; // 问题所在!
private int value = 0;
public void writer() {
value = 42;
flag = true; // 在另一个线程中,可能先看到这行!
}
public void reader() {
if (flag) {
// value可能看到0,而不是42!
System.out.println("Value: " + value);
}
}
}
并发三要素的具象化
// 1. 原子性破坏示例
i++; // 实际是:读取i → 计算i+1 → 写入i
// 2. 可见性破坏示例
// 线程A修改了共享变量,线程B却看到了旧值
// 3. 有序性破坏示例
// 指令重排导致初始化未完成就被使用
三、八大神器:构建线程安全的铜墙铁壁
神器1:synchronized - 最经典的解决方案
// 正确使用synchronized的姿势
public class SafeCounter {
private int count = 0;
private final Object lock = new Object(); // 专用锁对象
// 方法1:同步方法
public synchronized void increment() {
count++;
}
// 方法2:同步块(更细粒度控制)
public void safeIncrement() {
synchronized (lock) {
count++;
}
}
// 双重检查锁定的正确实现(单例模式)
public class Singleton {
private static volatile Singleton instance; // 必须volatile!
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
}
神器2:Atomic家族 - 无锁并发利器
import java.util.concurrent.atomic.*;
public class AtomicDemo {
// 原子整数
private AtomicInteger counter = new AtomicInteger(0);
// 原子引用
private AtomicReference<User> userRef = new AtomicReference<>();
// 原子数组
private AtomicIntegerArray array = new AtomicIntegerArray(10);
// 累加器(更高性能的统计)
private LongAdder adder = new LongAdder(); // JDK8+
public void demo() {
// CAS操作
int oldValue, newValue;
do {
oldValue = counter.get();
newValue = oldValue + 1;
} while (!counter.compareAndSet(oldValue, newValue));
// 简化API
counter.incrementAndGet();
adder.increment();
// 原子更新复杂对象
User oldUser, newUser;
do {
oldUser = userRef.get();
newUser = updateUser(oldUser);
} while (!userRef.compareAndSet(oldUser, newUser));
}
}
神器3:Concurrent集合 - 高性能线程安全容器
public class ConcurrentCollectionDemo {
// 1. ConcurrentHashMap - 分段锁实现
private ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();
public void safeCacheOperation() {
// 线程安全的putIfAbsent
cache.putIfAbsent("key", computeExpensiveValue());
// 并发安全的遍历
cache.forEach((k, v) -> process(k, v));
// 原子更新
cache.compute("key", (k, v) -> v == null ? 1 : (Integer)v + 1);
}
// 2. CopyOnWriteArrayList - 读多写少场景
private CopyOnWriteArrayList<String> logList = new CopyOnWriteArrayList<>();
public void logOperation() {
// 写时复制,读操作完全无锁
logList.add("new log"); // 每次add都会复制内部数组
// 适合监听器列表等场景
for (String log : logList) { // 遍历的是快照,线程安全
processLog(log);
}
}
// 3. ConcurrentLinkedQueue - 高性能队列
private ConcurrentLinkedQueue<Task> taskQueue = new ConcurrentLinkedQueue<>();
// 4. BlockingQueue - 生产者消费者模式
private BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<>(1000);
}
神器4:ThreadLocal - 线程私有变量
// ThreadLocal的正确使用姿势
public class ThreadLocalDemo {
// 1. SimpleDateFormat的安全用法
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public String formatDate(Date date) {
return dateFormatHolder.get().format(date); // 每个线程有自己的实例
}
// 2. 用户上下文传递
public class UserContextHolder {
private static final ThreadLocal<User> currentUser = new ThreadLocal<>();
public static void set(User user) {
currentUser.set(user);
}
public static User get() {
return currentUser.get();
}
public static void clear() {
currentUser.remove(); // 必须清理,防止内存泄漏!
}
}
// 3. 数据库连接管理
public class ConnectionHolder {
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<>();
public static Connection getConnection() {
Connection conn = connectionHolder.get();
if (conn == null) {
conn = DataSource.getConnection();
connectionHolder.set(conn);
}
return conn;
}
public static void close() {
Connection conn = connectionHolder.get();
if (conn != null) {
try { conn.close(); } catch (SQLException e) { /* ignore */ }
connectionHolder.remove(); // 关键!
}
}
}
}
神器5:Lock框架 - 更灵活的锁控制
import java.util.concurrent.locks.*;
public class LockFrameworkDemo {
// ReentrantLock - 可重入锁
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void transfer(Account from, Account to, BigDecimal amount) {
lock.lock(); // 手动获取锁
try {
// 业务逻辑
from.withdraw(amount);
to.deposit(amount);
// 条件等待
while (!conditionSatisfied()) {
condition.await(); // 释放锁并等待
}
condition.signalAll(); // 唤醒等待线程
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock(); // 必须在finally中释放!
}
}
// ReadWriteLock - 读写分离锁
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
public Object readData(String key) {
readLock.lock();
try {
return cache.get(key); // 允许多个读线程并发
} finally {
readLock.unlock();
}
}
public void writeData(String key, Object value) {
writeLock.lock();
try {
cache.put(key, value); // 只允许一个写线程
} finally {
writeLock.unlock();
}
}
}
神器6:并发工具类 - JDK的并发武器库
import java.util.concurrent.*;
public class ConcurrentUtilsDemo {
// 1. CountDownLatch - 多线程等待
public void batchProcess(List<Task> tasks) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(tasks.size());
for (Task task : tasks) {
executor.submit(() -> {
try {
task.execute();
} finally {
latch.countDown(); // 完成一个任务
}
});
}
latch.await(); // 等待所有任务完成
System.out.println("所有任务完成!");
}
// 2. CyclicBarrier - 线程栅栏
public void multiPhaseCalculation() {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程完成第一阶段");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
phase1();
barrier.await();
phase2();
barrier.await();
}).start();
}
}
// 3. Semaphore - 信号量(限流)
public class ConnectionPool {
private final Semaphore semaphore = new Semaphore(10); // 最多10个连接
public Connection getConnection() throws InterruptedException {
semaphore.acquire(); // 获取许可
return createConnection();
}
public void releaseConnection(Connection conn) {
closeConnection(conn);
semaphore.release(); // 释放许可
}
}
// 4. CompletableFuture - 异步编程
public CompletableFuture<User> getUserAsync(Long userId) {
return CompletableFuture.supplyAsync(() -> {
return userDao.findById(userId); // 异步执行
}).exceptionally(ex -> {
log.error("查询用户失败", ex);
return User.anonymous();
});
}
}
神器7:不可变对象 - 最简单的线程安全
// 不可变对象的黄金法则
public final class ImmutableUser { // 1. final类
private final Long id; // 2. final字段
private final String name;
private final List<String> roles; // 3. 引用类型需要特殊处理
// 4. 构造时初始化所有字段
public ImmutableUser(Long id, String name, List<String> roles) {
this.id = id;
this.name = name;
// 防御性复制
this.roles = Collections.unmodifiableList(new ArrayList<>(roles));
}
// 5. 不提供setter方法
// 6. 返回不可变视图
public List<String> getRoles() {
return Collections.unmodifiableList(roles);
}
// 7. 如需修改,返回新对象
public ImmutableUser withName(String newName) {
return new ImmutableUser(this.id, newName, this.roles);
}
}
// 枚举实现单例(线程安全)
public enum Singleton {
INSTANCE;
public void service() {
// 线程安全的方法
}
}
神器8:性能与安全兼备的并发模式
// 模式1:线程封闭(Thread Confinement)
public class ThreadConfinementDemo {
// 栈封闭 - 局部变量是线程安全的
public void process() {
List<String> localList = new ArrayList<>(); // 每个线程有自己的实例
// 安全操作localList
}
// ThreadLocal封闭
private ThreadLocal<SimpleDateFormat> formatHolder = ...;
}
// 模式2:不变性(Immutability)
// 使用不可变对象和不可变集合
// 模式3:保护性复制(Defensive Copy)
public class DefensiveCopyDemo {
private final List<String> data;
public DefensiveCopyDemo(List<String> input) {
// 构造时复制
this.data = new ArrayList<>(input);
}
public List<String> getData() {
// 返回时复制
return new ArrayList<>(data);
}
}
5308

被折叠的 条评论
为什么被折叠?



