深入解析 Java 中的 synchronized 与 Lock:线程同步机制的核心区别与应用场景

问题引入:多线程环境下的资源竞争

public class Main3 {
    public static void main(String[] args) {
        // 创建资源类
        ticket ticket = new ticket();

        new Thread(() ->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "线程1").start();
        new Thread(() ->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "线程2").start();
        new Thread(() ->{
            for (int i = 0; i < 50; i++) {
                ticket.sale();
            }
        }, "线程3").start();

    }
}

// 资源类(票)
class ticket {
    int ticketNum = 50;

    // 卖票方法
    void sale () {
        if (ticketNum > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + ticketNum-- + "张票");
        }
    }
}

当三个线程并发执行售票操作时,会出现以下问题:

  • 超卖(卖出超过库存数量的票)

  • 重复售票(同一票号被多次卖出)

  • 票号跳跃(打印顺序不符合预期)

未加锁前,多个线程卖票存在支援抢占

线程1卖出了第50张票
线程1卖出了第49张票
线程1卖出了第48张票
.............
线程2卖出了第1张票
线程1卖出了第11张票
线程3卖出了第25张票

 Lock锁

Lock是一个接口

​锁分为公平锁和非公平锁

公平锁:所有线程排队执行,不能插队

非公平锁:线程可以插队,cpu根据实际情况最大化提高效率

ReentrantLock默认是非公平锁

	// 不传参数,默认非公平锁
    public ReentrantLock() {
        sync = new NonfairSync(); 
    }
	// 传入fair,如果是true则是公平锁,如果是false则是非公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

二、同步方案对比

2.1 synchronized 实现方案

// 线程资源类(问题代码)
// 资源类(票)
class ticket {
    int ticketNum = 50;

    // 卖票方法
    synchronized void sale () {
        if (ticketNum > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + ticketNum-- + "张票");
        }
    }
}

2.2 Lock 实现方案

// 资源类(票)
class Ticket1 {
    int ticketNum = 50;
    // 默认
    Lock lock = new ReentrantLock();

    // 卖票方法
    synchronized void sale () {
        lock.lock();
        
        if (ticketNum > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + ticketNum-- + "张票");
        }
        
        lock.unlock();
    }
}

三、核心差异深度解析

3.1 实现层级

特性synchronizedLock
实现方式JVM 内置关键字Java API 接口
类结构自动关联对象监视器需要显式实例化锁对象
字节码实现通过 monitorenter/monitorexit 指令通过 AQS 队列同步器实现

3.2 锁管理机制

特性synchronizedLock
锁获取自动获取和释放必须显式调用 lock()/unlock()
异常处理自动释放锁需在 finally 块中确保释放
死锁风险无显式释放问题忘记 unlock() 会导致死锁

3.3 功能特性对比

特性synchronizedLock
可中断性不支持支持 lockInterruptibly()
超时机制不支持支持 tryLock(long, TimeUnit)
公平性仅非公平锁支持公平/非公平策略
条件变量通过 wait()/notify()支持多个 Condition 对象
锁状态查询不支持提供 isLocked() 等方法

3.4 性能表现

  • Java 6 前:synchronized 性能显著低于 Lock

  • Java 6+:引入锁升级机制后性能差距缩小

  • 适用场景:

    • 低竞争:优先 synchronized(JVM 自动优化)

    • 高竞争:考虑使用 Lock 的精细化控制

如何选择

推荐使用 synchronized 的场景:

  1. 简单的同步代码块

  2. 方法级别的同步控制

  3. 不需要高级锁特性的情况

  4. 资源竞争不激烈的场景

推荐使用 Lock 的场景:

  1. 需要可中断的锁获取机制

  2. 要求超时获取锁的功能

  3. 需要多个条件变量的复杂同步

  4. 需要公平锁策略

  5. 需要获取锁状态信息

  6. 细粒度的同步控制需求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值