Skip to content

synchronized vs Lock 对比

没有最好的,只有最适合的。

核心区别

对比项synchronizedLock (ReentrantLock)
获取/释放自动手动
公平性非公平可配置
超时等待✅ tryLock(timeout)
中断等待✅ lockInterruptibly()
条件变量一个(Object)多个(Condition)
性能JDK 6+ 已优化相当或更好

场景一:简单互斥

java
// ✅ synchronized:简单场景首选
public class SimpleCounter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}

// ✅ ReentrantLock:功能更多
public class SimpleCounterWithLock {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

建议:简单互斥用 synchronized,代码更简洁。

场景二:避免死锁

java
// ❌ synchronized:可能死锁
public void transfer(Account a, Account b, int amount) {
    synchronized (a) {
        synchronized (b) {
            // 转账
        }
    }
}

// ✅ ReentrantLock + tryLock:避免死锁
public boolean transfer(Account a, Account b, int amount) {
    // 固定顺序获取锁
    if (a.id < b.id) {
        if (!a.lock.tryLock(1, TimeUnit.SECONDS)) return false;
    } else {
        if (!b.lock.tryLock(1, TimeUnit.SECONDS)) return false;
    }
    try {
        // 转账
        return true;
    } finally {
        if (a.id < b.id) a.lock.unlock();
        else b.lock.unlock();
    }
}

建议:多锁场景用 tryLock 避免死锁。

场景三:可中断等待

java
// ❌ synchronized:不支持中断
public synchronized void process() throws InterruptedException {
    while (condition) {
        wait();  // 不响应中断
    }
}

// ✅ ReentrantLock:可中断
public void process() throws InterruptedException {
    lock.lockInterruptibly();
    try {
        while (!conditionMet) {
            condition.await();  // 可被中断
        }
    } finally {
        lock.unlock();
    }
}

建议:需要响应中断时用 ReentrantLock。

场景四:多个条件变量

java
// ❌ synchronized:只有一个条件
public class SingleCondition {
    private final Object lock = new Object();
    private boolean notEmpty = false;
    private boolean notFull = false;

    public void put(Object item) throws InterruptedException {
        synchronized (lock) {
            while (notFull) {  // 只能用 while
                lock.wait();
            }
            // 生产
            notEmpty = true;
            lock.notifyAll();
        }
    }

    public Object take() throws InterruptedException {
        synchronized (lock) {
            while (!notEmpty) {  // 没法区分「不等」和「不等满」
                lock.wait();
            }
            // 消费
            notFull = true;
            lock.notifyAll();
        }
    }
}

// ✅ ReentrantLock:多个条件
public class MultiCondition {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public void put(Object item) throws InterruptedException {
        lock.lock();
        try {
            while (isFull()) {
                notFull.await();  // 只等「不满」的条件
            }
            // 生产
            notEmpty.signal();    // 只通知「非空」等待的线程
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (isEmpty()) {
                notEmpty.await();  // 只等「非空」的条件
            }
            // 消费
            notFull.signal();      // 只通知「不满」等待的线程
        } finally {
            lock.unlock();
        }
    }
}

建议:需要多个等待条件时用 Condition。

场景五:读多写少

java
// ❌ synchronized:读写都互斥
private int value = 0;

public synchronized int read() { return value; }
public synchronized void write(int v) { value = v; }

// ✅ ReadWriteLock:读并发,写独占
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private int value = 0;

public int read() {
    rwLock.readLock().lock();
    try {
        return value;
    } finally {
        rwLock.readLock().unlock();
    }
}

public void write(int v) {
    rwLock.writeLock().lock();
    try {
        value = v;
    } finally {
        rwLock.writeLock().unlock();
    }
}

建议:读多写少用 ReadWriteLock。

性能对比

java
public class PerformanceTest {

    private static final int THREADS = 8;
    private static final int ITERATIONS = 10_000_000;

    // synchronized 版本
    private int counter1 = 0;
    private final Object lock1 = new Object();

    // ReentrantLock 版本
    private int counter2 = 0;
    private final ReentrantLock lock2 = new ReentrantLock();

    public static void main(String[] args) throws Exception {
        PerformanceTest test = new PerformanceTest();

        // 测试 synchronized
        long start = System.nanoTime();
        test.testSync();
        long syncTime = System.nanoTime() - start;

        // 测试 ReentrantLock
        start = System.nanoTime();
        test.testLock();
        long lockTime = System.nanoTime() - start;

        System.out.println("synchronized: " + syncTime / 1_000_000 + " ms");
        System.out.println("ReentrantLock: " + lockTime / 1_000_000 + " ms");
        System.out.println("差异: " + String.format("%.1f%%", (lockTime - syncTime) * 100.0 / syncTime));
    }
}

典型结果(JDK 17, 8 核):

synchronized: 120 ms
ReentrantLock: 125 ms
差异: 4.2%

结论:现代 JDK 下,两者性能差异不大。

选择决策树

需要同步?

    ├─ 需要 tryLock / 超时? ────→ ReentrantLock

    ├─ 需要可中断? ──────────────→ ReentrantLock

    ├─ 需要多个条件变量? ─────────→ ReentrantLock

    ├─ 读多写少? ────────────────→ ReentrantReadWriteLock

    └─ 以上都不需要? ────────────→ synchronized(首选)

最佳实践

优先用 synchronized

java
// ✅ 推荐:简单互斥
public class Service {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }
}

复杂场景用 Lock

java
// ✅ 推荐:需要高级特性
public class AdvancedService {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();

    public void awaitWithTimeout() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            if (!conditionMet) {
                notEmpty.await(5, TimeUnit.SECONDS);
            }
        } finally {
            lock.unlock();
        }
    }
}

永远在 finally 中释放 Lock

java
// ❌ 危险
lock.lock();
try {
    // 可能抛异常
    doSomething();
} catch (Exception e) {
    // 出错了,但锁没释放
}

// ✅ 安全
lock.lock();
try {
    doSomething();
} finally {
    lock.unlock();  // 一定释放
}

总结

场景推荐
简单互斥synchronized
多锁 + 避免死锁ReentrantLock + tryLock
可中断等待ReentrantLock
多个条件变量ReentrantLock + Condition
读多写少ReentrantReadWriteLock

原则

  1. 简单场景用 synchronized(更简洁、更安全)
  2. 需要高级特性时用 Lock
  3. 记住在 finally 中释放锁

基于 VitePress 构建