返回

synchronized 和 ReentrantLock 的异同:分毫不差,不差分毫

后端

深入了解锁:Java 中 synchronized 和 ReentrantLock 的异同

在并发的世界中,协调对共享资源的访问至关重要。锁是计算机科学中使用的关键机制,可以帮助我们实现这一点。在 Java 中,synchronized 和 ReentrantLock 是常用的锁类型,它们有其独特的特性和应用场景。

synchronized 和 ReentrantLock:一瞥

synchronized

  • 使用 synchronized 获取。
  • 内置锁,不允许同一线程多次获取。
  • 非公平锁,不保证线程获取锁的顺序。
  • 性能较低,因为它是一个内置锁。
  • 安全性较低,不提供中断支持或条件变量。
  • 适用于保护共享变量的访问。

ReentrantLock

  • 通过显式调用 lock() 方法获取。
  • 可重入锁,允许同一线程多次获取。
  • 可以是公平锁或非公平锁。
  • 性能较高,因为它是一个用户态锁。
  • 安全性较高,提供中断支持和条件变量。
  • 适用于保护共享资源的访问。

主要差异

  • 获取锁的方式: synchronized 使用关键字,而 ReentrantLock 使用显式调用。
  • 锁的类型: synchronized 是内置锁,而 ReentrantLock 是可重入锁。
  • 公平性: synchronized 是非公平锁,而 ReentrantLock 可以是公平锁。
  • 性能: synchronized 性能较低,而 ReentrantLock 性能较高。
  • 安全性: ReentrantLock 提供更高级别的安全性功能。
  • 使用场景: synchronized 用于保护共享变量,而 ReentrantLock 用于保护共享资源。

如何选择合适的锁

选择合适的锁取决于你的特定需要。这里有一些准则:

  • 保护共享变量?使用 synchronized。
  • 保护共享资源?使用 ReentrantLock。
  • 需要可重入性?使用 ReentrantLock。
  • 需要公平性?使用 ReentrantLock 的公平模式。
  • 需要高性能?使用 synchronized。
  • 需要高级安全性?使用 ReentrantLock。

示例代码

synchronized

public class SynchronizedExample {
    private int count = 0;

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

ReentrantLock

public class ReentrantLockExample {
    private ReentrantLock lock = new ReentrantLock();
    private int count = 0;

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

常见问题解答

  1. 什么是可重入锁?
    可重入锁允许同一线程多次获取同一个锁,这在递归或嵌套代码块中很有用。
  2. 公平锁和非公平锁有什么区别?
    公平锁保证线程获取锁的顺序是按照它们请求锁的顺序,而非公平锁不保证这一点。
  3. 何时应该使用 synchronized,何时应该使用 ReentrantLock?
    一般来说,如果只需要保护共享变量,可以使用 synchronized,否则使用 ReentrantLock。
  4. ReentrantLock 的中断支持有什么好处?
    中断支持允许线程在等待锁时响应中断,这对于处理时间敏感任务非常有用。
  5. ReentrantLock 的条件变量有什么好处?
    条件变量允许线程等待特定条件,例如等待队列非空或某个条件为真,然后继续执行。