Java 常见的加锁方法
关键字Synchronized 与 ReentrantLock
Synchronized
在Java中,synchronized 是一种用于实现线程同步的关键字。
public synchronized void synchronizedMethod() {
// 这里的代码是线程安全的
// ...
}
在上述例子中,整个方法被标记为 synchronized,这意味着只有一个线程能够同时执行这个方法。其他线程需要等待当前线程执行完毕后才能访问该方法。
ReentrantLock
ReentrantLock 是 Java 中用于实现可重入锁的一种机制。它提供了比传统的 synchronized 关键字更灵活的锁定方式
//初始化锁
ReentrantLock lock = new ReentrantLock();
//锁使用于代码中
lock.lock();
try {
// 代码块,执行需要互斥的操作
} finally {
lock.unlock(); // 在 finally 块中确保释放锁,以防发生异常
}
ReentrantLock的可重入性
lock.lock();
try {
// 第一次获取锁
lock.lock();
try {
// 第二次获取锁
// 执行代码块
} finally {
lock.unlock(); // 释放第二次获取的锁
}
// 执行代码块
} finally {
lock.unlock(); // 释放第一次获取的锁
}
ReentrantLock 默认是非公平锁,但可以通过构造函数参数设置为公平锁:
ReentrantLock fairLock = new ReentrantLock(true); // 公平锁
ReentrantLock unfairLock = new ReentrantLock(); // 非公平锁
Synchronized 和 ReentrantLock的区别:
- 实现方式:
Synchronized 是一种内置的、隐式的同步机制,通过在方法或代码块上加关键字 synchronized 来实现。它是基于 JVM 的监视器锁(Monitor Lock)实现的。
ReentrantLock 是一个显式的锁实现,是 java.util.concurrent 包中的一部分。它提供了更灵活的方式来控制锁的获取和释放。 - 灵活性:
ReentrantLock 提供了更多的灵活性,例如可中断锁、定时锁、公平锁等。相比之下,Synchronized 的功能较为有限。 - 可重入性:
两者都是可重入的,即一个线程可以多次获得同一个锁。这意味着在同一线程内,可以多次调用同步方法而不会死锁。 - 性能:
在某些情况下,ReentrantLock 的性能可能优于 Synchronized。
ReentrantLock 提供了更多的控制,但在简单的同步需求下,Synchronized 的开销可能更小。 - 异常处理:
ReentrantLock 允许更灵活的异常处理,你可以在 try-finally 块中显式释放锁,而 Synchronized 则在方法或代码块结束时自动释放锁。