程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

lock更强大, synchronized更简单!

balukai 2025-07-10 13:08:35 文章精选 2 ℃

lock 和 synchronized 都是 Java 中用来解决线程同步的机制,但是它们有以下几个区别:

1. lock 是一个接口,synchronized 是 Java 中的关键字,synchronized 内置于 Java 中,lock 需要额外导入
java.util.concurrent.locks 包。

2. lock 需要手动获取和释放锁,这可能导致死锁。而synchronized 会自动释放锁,所以不会出现忘记释放锁导致的死锁问题。

例如以下代码:

使用 lock:

Lock lock = new ReentrantLock();
lock.lock();
// do something...
// 如果这里忘记调用 lock.unlock() 释放锁,就会发生死锁

使用 synchronized :

public void method() {  
    synchronized (this) {  
        // do something...
    } 
}
// 这里不需要手动释放锁,JVM 会自动释放

3. lock 可以尝试获取锁,而synchronized 是直接获取锁,或者等待获取锁。例如:

if (lock.tryLock()) {  
    try {  
        // manipulate shared resource  
    } finally {  
        lock.unlock();  
    }  
} else { 
    // do something else  
} 

4. lock可以具有不同的锁定机制(公平锁/非公平锁),而synchronized只有非公平锁。

5. synchronized 可重入锁,同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁。ReentrantLock 也可以是可重入的,需要在创建时设置参数为 true。

6. synchronized 无法知道目前有没有锁定和正在等待锁定的线程,ReentrantLock可以获取这些信息。

例如:

- lock.isLocked() - 检查锁是否被任何线程占用
- lock.getHoldCount() - 获取锁被当前线程重入的次数
- lock.hasQueuedThreads() - 检查是否有线程正在等待获得锁
- lock.getQueueLength() - 获取正在等待获得锁的线程数量示例代码:

Lock lock = new ReentrantLock();

// 检查锁是否被占用
boolean locked = lock.isLocked();

// 获取重入次数
int holdCount = lock.getHoldCount(); 

// 检查是否有等待线程
boolean hasQueued = lock.hasQueuedThreads();  

// 获取等待线程数量
int queueLength = lock.getQueueLength();

而使用 synchronized 的话,没有这些方法可以获取锁的相关信息:

public synchronized void method() {
    // 没有对应的方法获取锁信息
}

所以,总体来说,lock比synchronized更灵活方便,但是synchronized由JVM内置实现,对线程安全提供了更强的保证,且避免了手动获取和释放锁可能导致的问题,所以也更简便。选择哪个还是需要根据具体情况而定。

最近发表
标签列表