搞懂Java多线程必知的7大锁策略(实战干货)

前言:锁的七十二变

多线程编程就像开碰碰车(线程)进游乐场(共享资源),没点规则肯定要撞车!!今天咱们来扒一扒Java中那些让人又爱又恨的锁策略,看完保证你写线程安全代码时不再靠玄学(疯狂踩坑)!


一、乐观锁 vs 悲观锁(心态大不同)

1.1 悲观锁:总有刁民想害朕

// 典型代表:synchronized关键字
public synchronized void transfer(Account target, int amount) {
    // 默认认为每次操作都会冲突,直接上锁!
    this.balance -= amount;
    target.balance += amount;
}

使用场景:写操作频繁、冲突概率高的场景(比如秒杀系统)

1.2 乐观锁:世界充满爱

// 典型实现:CAS(Compare And Swap)
AtomicInteger count = new AtomicInteger(0);

public void safeIncrement() {
    int oldValue;
    do {
        oldValue = count.get();  // 先读取当前值
    } while (!count.compareAndSet(oldValue, oldValue + 1)); // 尝试更新
}

(敲黑板):版本号机制在数据库中的应用:

UPDATE products 
SET stock = stock - 1, version = version + 1 
WHERE id = 100 AND version = 1;  -- 这里的version就是乐观锁

二、读写锁(读多写少的神器)

2.1 读写分离的智慧

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

void readData() {
    rwLock.readLock().lock();
    try {
        // 多个线程可以同时读
    } finally {
        rwLock.readLock().unlock();
    }
}

void writeData() {
    rwLock.writeLock().lock();
    try {
        // 同一时间只允许一个线程写
    } finally {
        rwLock.writeLock().unlock();
    }
}

性能对比:在100次读+1次写的场景下,读写锁比互斥锁快10倍以上!!!


三、自旋锁(头铁的锁)

3.1 旋转跳跃我不停歇

// AtomicInteger的自旋实现
public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

适用场景

  • 线程阻塞代价高(内核态切换)
  • 临界区代码执行时间极短(建议小于1ms)

(注意):长时间自旋会疯狂消耗CPU,慎用!!


四、公平锁 vs 非公平锁(排队哲学)

4.1 公平锁的强迫症

new ReentrantLock(true);  // 开启公平模式

优点:不会饿死线程
代价:吞吐量下降约30%(要维护队列)

4.2 非公平锁的狼性文化

new ReentrantLock();  // 默认非公平

实测场景:10个线程竞争时,非公平锁的吞吐量是公平锁的2倍!


五、可重入锁(套娃高手)

5.1 递归不翻车的秘密

public synchronized void methodA() {
    methodB();  // 可以重复获取同一把锁
}

public synchronized void methodB() {
    // ...
}

(灵魂拷问):如果synchronized不可重入,递归调用会怎样?→ 直接死锁!!


锁策略选择速查表

场景特征推荐锁策略避坑指南
读多写少(如缓存)读写锁注意写锁的获取顺序
临界区执行时间极短(<1ms)自旋锁避免长时间自旋
需要保证绝对公平公平锁做好性能下降的心理准备
线程切换代价高(内核态操作)自旋锁+超时机制设置合理的自旋次数
嵌套调用/递归场景可重入锁注意锁的释放次数
写操作频繁(如库存扣减)悲观锁配合事务使用

实战中的骚操作

锁升级策略(JDK6+)

  1. 无锁 → 偏向锁 → 轻量级锁 → 重量级锁
  2. 对象头中的Mark Word会记录锁状态变化

锁消除(JVM优化)

// 虽然用了synchronized,但JVM检测到没有线程安全问题
public String concat(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}

(神奇):JVM会自动去掉这里的同步锁!


结语:没有银弹

实际开发中经常需要混合使用多种锁策略,比如:

  • 读写锁 + 乐观锁(如MySQL的MVCC)
  • 自旋锁 + 超时机制(防止死等)
  • 可重入锁 + 公平性选择

记住:锁的粒度越细,性能越好,但复杂度越高。大家在面试被问锁的时候,可以甩出今天这些干货,绝对让面试官眼前一亮(亲测有效)!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值