最佳实践
并发编程的最佳实践和常见问题解决方案。
1. 避免死锁
1.1 死锁条件
- 互斥条件
- 占有并等待
- 不可抢占
- 循环等待
1.2 常见场景
java
// ❌ 错误:锁顺序不一致
public void method1() {
synchronized (lockA) {
synchronized (lockB) { }
}
}
public void method2() {
synchronized (lockB) {
synchronized (lockA) { } // 可能死锁
}
}
// ✅ 正确:统一锁顺序
public void method1() {
synchronized (lockA) {
synchronized (lockB) { }
}
}
public void method2() {
synchronized (lockA) { // 保持一致
synchronized (lockB) { }
}
}1.3 解决方案
- 统一加锁顺序
- 使用 tryLock 超时
- 避免嵌套锁
2. 线程池配置
2.1 参数计算
java
int cpuCores = Runtime.getRuntime().availableProcessors();
// CPU密集型
int cpuIntensive = cpuCores + 1;
// IO密集型
int ioIntensive = cpuCores * 2;2.2 推荐配置
| 场景 | 核心线程 | 最大线程 | 队列 |
|---|---|---|---|
| CPU 密集 | N+1 | N+1 | 小队列 |
| IO 密集 | 2N | 4N | 较大队列 |
3. 避免共享可变状态
3.1 使用 ThreadLocal
java
// ❌ 错误:共享可变状态
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// ✅ 正确:使用 ThreadLocal
private static final ThreadLocal<SimpleDateFormat> sdf =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public String format(Date date) {
return sdf.get().format(date);
}3.2 使用不可变对象
java
// 使用不可变类
public final class ImmutableUser {
private final String name;
private final int age;
public ImmutableUser(String name, int age) {
this.name = name;
this.age = age;
}
// 只有 getter,没有 setter
}4. 正确使用 volatile
java
// ✅ 适合:状态标志
private volatile boolean running = true;
// ❌ 不适合:复合操作
private volatile int count;
count++; // 非原子操作!应使用 AtomicInteger5. 场景速查表
| 场景 | 推荐方案 |
|---|---|
| 简单同步 | synchronized |
| 需要更多控制 | ReentrantLock |
| 读多写少 | ReentrantReadWriteLock |
| 计数器 | AtomicInteger |
| 高并发计数 | LongAdder |
| 异步编程 | CompletableFuture |
| 生产者消费者 | BlockingQueue |
| 线程复用 | ThreadPoolExecutor |
| 等待多线程完成 | CountDownLatch |
| 限流 | Semaphore |