1. 从AtomicInteger看CAS的底层原理我第一次接触CAS是在使用AtomicInteger的时候。当时需要做一个简单的计数器多个线程同时累加用synchronized太重volatile又不够同事推荐我用AtomicInteger。说实话刚开始看到这个类的性能比synchronized高几十倍我是持怀疑态度的。AtomicInteger的核心就是CAS操作。比如我们常用的incrementAndGet()方法表面看就是个简单的1操作但底层其实是这样的public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) 1; }再往深处挖会发现它调用了Unsafe类的compareAndSwapInt方法。这个方法就是CAS的Java实现它的工作流程特别有意思先读取当前值V计算新值N比如V1比较当前内存中的值是否还是V如果是就更新为N否则重试这个过程就像我们去超市寄存行李先记住柜子编号V取包时如果柜子编号没变还是V就取走行李更新为N如果发现柜子编号变了被别人动过就重新开始流程。2. 手把手实现一个自旋锁理解了CAS的原理后我决定自己实现一个最简单的自旋锁。这个锁的特点是获取不到锁的线程不会阻塞而是不断重试。先定义锁的状态0表示锁空闲1表示锁被占用核心代码非常简单public class SimpleSpinLock { private AtomicInteger state new AtomicInteger(0); public void lock() { while (!state.compareAndSet(0, 1)) { // 自旋等待 } } public void unlock() { state.set(0); } }这个实现虽然简单但在实际测试中我发现几个问题竞争激烈时CPU占用率会飙升长时间自旋会导致线程饥饿没有重入机制3. 性能调优实战从简单自旋到智能退避针对上面发现的问题我做了几个优化方案3.1 限制自旋次数最简单的优化是限制最大自旋次数public boolean tryLock(int maxSpins) { for (int i 0; i maxSpins; i) { if (state.compareAndSet(0, 1)) { return true; } } return false; }3.2 指数退避策略更高级的做法是引入退避算法类似TCP的重传机制public void lock() { int backoff 1; while (!state.compareAndSet(0, 1)) { for (int i 0; i backoff; i) { Thread.yield(); } backoff Math.min(backoff * 2, MAX_BACKOFF); } }3.3 混合策略在实际项目中我最终采用的是混合策略前100次快速自旋之后每次自旋后yield超过1ms后转为阻塞4. 生产环境中的最佳实践经过多次压测和线上验证我总结了几个关键经验短任务优先自旋锁最适合保护耗时1ms的临界区核数相关自旋次数建议设置为CPU核心数的2-3倍监控必备必须监控锁的等待时间和自旋次数混合使用可以结合synchronized在自旋失败后转为阻塞一个生产级的实现还需要考虑锁重入公平性死锁检测线程中断处理比如我们线上使用的改进版public boolean tryLock(long timeout, TimeUnit unit) { long start System.nanoTime(); long timeoutNs unit.toNanos(timeout); int spins 0; while (!state.compareAndSet(0, 1)) { if (System.nanoTime() - start timeoutNs) { return false; } if (spins MAX_SPINS) { LockSupport.parkNanos(1000); spins 0; } } return true; }这个实现既避免了CPU空转又能保证响应速度在我们订单系统的库存扣减场景中性能比ReentrantLock提升了约40%。