一句话说透Java里面的synchronized和Lock的区别

171 阅读2分钟

一句话总结
synchronized 是“傻瓜式自动锁”,简单但功能有限;Lock 是“手动挡高级锁”,灵活但需细心操作。


一、核心区别对比

对比项synchronizedLock(如ReentrantLock)
锁获取方式自动获取与释放(代码块结束)手动 lock() 和 unlock()
中断响应❌ 不可中断✅ 支持 lockInterruptibly()
公平性❌ 非公平锁(默认)✅ 可设置为公平锁
条件变量仅一个等待队列(wait()/notify()✅ 支持多个 Condition
性能JDK优化后与Lock接近,低竞争下更优高竞争场景更灵活
锁状态无法查看锁是否被占用✅ 可查询锁状态(tryLock()
适用场景简单同步需求复杂同步控制(如超时、公平性)

二、具体差异详解

1. 锁的获取与释放

  • synchronized

    • 自动管理:进入同步代码块自动加锁,退出时自动释放。

    • 风险:若代码异常退出,锁会自动释放,避免死锁。

    synchronized (obj) {  
        // 自动加锁  
        // ...  
    } // 自动释放锁  
    
  • Lock

    • 手动控制:必须显式调用 lock() 和 unlock(),通常放在 try-finally 中确保释放。

    • 风险:忘记 unlock() 会导致死锁!

    Lock lock = new ReentrantLock();  
    lock.lock();  
    try {  
        // ...  
    } finally {  
        lock.unlock(); // 必须手动释放  
    }  
    

2. 中断与超时控制

  • synchronized

    • 线程在等待锁时 无法被中断,只能死等。

    synchronized (obj) {  
        // 线程会一直阻塞,直到获取锁  
    }  
    
  • Lock

    • 可中断等待:通过 lockInterruptibly() 允许其他线程中断等待。
    • 超时获取tryLock(5, TimeUnit.SECONDS) 尝试5秒,超时放弃。
    if (lock.tryLock(3, TimeUnit.SECONDS)) {  
        try { /* ... */ } finally { lock.unlock(); }  
    } else {  
        // 超时未获取锁,执行其他逻辑  
    }  
    

3. 公平性

  • synchronized

    • 非公平锁:谁抢到锁谁用,可能导致线程“饥饿”。
  • Lock

    • 可设公平锁:按请求顺序分配锁(但性能略低)。
    Lock fairLock = new ReentrantLock(true); // 公平锁  
    

4. 条件变量(Condition)

  • synchronized

    • 只能通过 wait() 和 notify() 控制一个等待队列。

    synchronized (obj) {  
        while (条件不满足) {  
            obj.wait(); // 所有线程在同一个队列等待  
        }  
    }  
    
  • Lock

    • 支持多个 Condition,实现精细控制(如生产者-消费者模型)。

    Lock lock = new ReentrantLock();  
    Condition notFull = lock.newCondition();  // 队列未满条件  
    Condition notEmpty = lock.newCondition(); // 队列非空条件  
    
    // 生产者:队列满时等待 notFull  
    public void produce() {  
        lock.lock();  
        try {  
            while (queue.isFull()) {  
                notFull.await();  
            }  
            queue.add(item);  
            notEmpty.signal(); // 唤醒消费者  
        } finally {  
            lock.unlock();  
        }  
    }  
    

三、使用场景建议

场景推荐选择理由
简单同步(如计数器)synchronized代码简洁,自动管理锁
需要超时或中断Lock灵活控制锁的获取与释放
公平锁需求Lock支持按请求顺序分配锁
复杂线程协作Lock + Condition多条件队列实现精细控制

四、总结

  • synchronized:适合简单场景,避免手动管理锁的复杂性。
  • Lock:适合高并发、复杂同步逻辑,提供更多控制权。

口诀
「synchronized 自动挡,简单场景它最强
Lock 手动更灵活,超时中断公平锁
按需选择两兄弟,代码安全又高效!」