在上一期我们探讨了并发编程的基础概念和常见面试题后,今天我们继续深入这个让无数开发者又爱又恨的领域。作为Java开发者,我经历过太多因为并发问题导致的深夜加班——从诡异的死锁到难以复现的数据竞争,这些经历让我深刻认识到理解并发原理的重要性。
AbstractQueuedSynchronizer(AQS)是Java并发包的核心基础框架,理解它就能理解ReentrantLock、CountDownLatch等同步器的本质。AQS内部维护了一个FIFO队列和state状态变量,通过CAS操作实现线程安全。
java复制// 典型AQS实现示例
public class MyLock extends AbstractQueuedSynchronizer {
protected boolean tryAcquire(int arg) {
return compareAndSetState(0, 1);
}
protected boolean tryRelease(int arg) {
setState(0);
return true;
}
}
注意:AQS的tryAcquire/tryRelease方法需要开发者自己实现,这是模板方法设计模式的典型应用
ReentrantReadWriteLock通过分离读锁和写锁显著提升性能。其关键点在于:
java复制ReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();
JDK7的ConcurrentHashMap采用分段锁设计,而JDK8改为CAS+synchronized优化:
java复制ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.computeIfAbsent("key", k -> 1); // 线程安全的复合操作
适用于读多写少的场景,写入时复制整个数组:
实际经验:配置中心这类读多写少的场景特别适合使用CopyOnWriteArrayList
比较并交换(Compare And Swap)是CPU提供的原子指令:
java复制AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // 基于CAS的自增
在高并发场景下优于AtomicLong:
根据业务类型配置线程池:
java复制ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new CustomThreadFactory(),
new CustomRejectedPolicy());
通过扩展ThreadPoolExecutor实现监控:
使用jstack检测死锁:
jps获取Java进程IDjstack -l <pid>查看线程堆栈实际案例:我曾遇到过一个数据库连接池和业务锁顺序不一致导致的死锁,调整获取锁的顺序后解决
典型症状:
考察点:
关键点:
java复制CompletableFuture.supplyAsync(() -> queryFromDB())
.thenApplyAsync(result -> processData(result))
.thenAcceptAsync(processed -> saveToCache(processed))
.exceptionally(ex -> {
log.error("处理失败", ex);
return null;
});
java复制StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead();
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
// 读取数据
} finally {
lock.unlockRead(stamp);
}
}
Java并发压力测试工具:
分析线程转储时关注:
| 特性 | Actor模型 | 线程模型 |
|---|---|---|
| 通信方式 | 消息传递 | 共享内存 |
| 并发单位 | Actor | 线程 |
| 同步方式 | 异步非阻塞 | 同步/异步 |
| 适用场景 | 分布式系统 | 单机多核 |
响应式流的特性:
使用@Contended注解避免伪共享:
java复制@Contended
class VolatileLong {
volatile long value;
}
正确实现库存扣减:
锁的四种状态:
使用BlockingQueue实现:
java复制BlockingQueue<Task> queue = new LinkedBlockingQueue<>();
// 生产者
queue.put(task);
// 消费者
Task task = queue.take();
适合计算密集型任务:
常见实现方式:
根据业务需求权衡:
审查时特别注意:
使用工具检测并发问题:
虚拟线程特性:
从JDK5到JDK17的演进:
核心概念:
并发安全保证:
值得研究的项目:
在并发编程这条路上,我最大的体会是:理论理解是基础,但真正的能力来自于实际问题的解决。建议大家在理解原理后,多在实际项目中应用这些知识,遇到问题时深入分析,这样才能真正掌握并发编程的精髓。