Java并发编程与锁优化
并发编程在高性能场景下尤为重要,合理的锁策略能大幅提升吞吐量。
锁的类型与选择
| 锁类型 | 特点 | 适用场景 |
|---|---|---|
| synchronized | JVM内置,简单 | 低竞争场景 |
| ReentrantLock | 灵活,可中断 | 高竞争场景 |
| StampedLock | 读写锁,乐观读 | 读多写少 |
| CAS | 无锁,乐观 | 状态更新 |
| LongAdder | 分散计数 | 高并发计数 |
synchronized优化
锁升级过程
Java
┌─────────────────────────────────────┐
│ synchronized锁升级 │
├─────────────────────────────────────┤
│ │
│ 无锁 → 偏向锁 → 轻量锁 → 重量锁 │
│ │
│ 单线程 单线程 多线程交替 多线程竞争 │
│ 无竞争 可重入 CAS自旋 阻塞等待 │
│ │
└─────────────────────────────────────┘
锁优化技巧
Java
// 1. 减小锁范围
public void process() {
synchronized(this) {
// 只锁必要代码
criticalSection();
}
nonCriticalSection(); // 不锁
}
// 2. 锁分离(读写分离)
public class ReadWriteLockDemo {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public Object read() {
lock.readLock().lock();
try {
return data;
} finally {
lock.readLock().unlock();
}
}
public void write(Object value) {
lock.writeLock().lock();
try {
data = value;
} finally {
lock.writeLock().unlock();
}
}
}
// 3. 锁分段
public class StripedLock {
private final Lock[] locks = new Lock[16];
public void process(int key) {
locks[key & 0xF].lock(); // 按key分段加锁
try {
// ...
} finally {
locks[key & 0xF].unlock();
}
}
}
无锁编程
CAS原子操作
Java
// AtomicInteger内部使用CAS
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public int increment() {
return count.incrementAndGet(); // CAS自增
}
}
// AtomicReference
public class AtomicUpdater {
private AtomicReference<State> state = new AtomicReference<>();
public boolean update(State oldState, State newState) {
return state.compareAndSet(oldState, newState);
}
}
LongAdder高并发计数
Java
// 高并发计数:LongAdder优于AtomicInteger
public class HighConcurrencyCounter {
private LongAdder counter = new LongAdder();
public void increment() {
counter.increment(); // 分散计数,无竞争
}
public long sum() {
return counter.sum(); // 汇总所有计数器
}
}
// 对比:
// AtomicInteger:所有线程竞争一个变量
// LongAdder:分散到多个Cell,无竞争,最后汇总
并发容器选择
ConcurrentHashMap
Java
// JDK7:分段锁(Segment)
// JDK8:CAS+synchronized(桶级锁)
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
// 原子操作
map.putIfAbsent("key", "value");
map.computeIfAbsent("key", k -> computeValue());
// 批量操作(JDK8+)
map.forEach((k, v) -> process(k, v));
map.search(100, (k, v) -> searchValue(k, v));
CopyOnWriteArrayList
Java
// 适用:读多写极少
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 读:不加锁,直接返回
String value = list.get(0);
// 写:复制整个数组,加锁
list.add("new"); // 复制+加锁,性能低
并发队列
Java
// 高吞吐:ConcurrentLinkedQueue(无锁)
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("item");
String item = queue.poll();
// 阻塞队列:生产消费场景
ArrayBlockingQueue<String> bounded = new ArrayBlockingQueue<>(100);
bounded.put("item"); // 满时阻塞
String item = bounded.take(); // 空时阻塞
// 高性能阻塞队列:Disruptor
// RingBuffer实现,单线程可达百万级吞吐
线程池优化
线程池配置
Java
// 合理配置线程数
// CPU密集型:N + 1(N=CPU核数)
// IO密集型:2N 或更多
ThreadPoolExecutor executor = new ThreadPoolExecutor(
8, // 核心线程数
16, // 最大线程数
60, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000), // 任务队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
线程池监控
Java
// 监控线程池状态
executor.getActiveCount(); // 活动线程数
executor.getQueue().size(); // 队列大小
executor.getCompletedTaskCount(); // 完成任务数
// 动态调整
executor.setCorePoolSize(10);
executor.setMaximumPoolSize(20);
并发编程模式
生产者-消费者
Java
public class ProducerConsumer {
private BlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
// 生产者
public void produce(String item) throws InterruptedException {
queue.put(item);
}
// 消费者
public String consume() throws InterruptedException {
return queue.take();
}
}
Future异步计算
text
// CompletableFuture(JDK8+)
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> fetchData())
.thenApply(data -> processData(data))
.thenAccept(result -> saveResult(result));
// 组合多个Future
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> fetch1());
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> fetch2());
CompletableFuture<String> combined = f1.thenCombine(f2, (r1, r2) -> merge(r1, r2));
锁优化总结
| 场景 | 推荐方案 |
|---|---|
| 低竞争 | synchronized |
| 高竞争读多写少 | StampedLock乐观读 |
| 高竞争写多 | ReentrantLock |
| 状态更新 | CAS/AtomicXxx |
| 高并发计数 | LongAdder |
| 高并发Map | ConcurrentHashMap |
| 读多写极少 | CopyOnWriteArrayList |
| 生产消费 | BlockingQueue |
注意事项
synchronized已优化,低竞争场景足够
避免锁嵌套,防止死锁
LongAdder适合计数,AtomicInteger适合精确值
CopyOnWrite写操作性能差,只适合读多写极少
线程池队列大小影响响应时间和吞吐量
CompletableFuture适合异步编排,避免阻塞
要点总结
- synchronized锁升级:无锁→偏向→轻量→重量
- 高并发用CAS/LongAdder,无锁编程
- ConcurrentHashMap分段/桶级锁,高并发安全
- 线程池配置:CPU密集N+1,IO密集2N
- CompletableFuture异步编排,避免阻塞等待
📝 发现内容有误?点击此处直接编辑