ReentrantLock
类的概念
ReentrantLock
是Java中的一个可重入的互斥锁类,它提供了比synchronized
关键字更灵活的锁定机制。ReentrantLock
类实现了Lock
接口,支持公平锁和非公平锁两种模式。
ReentrantLock
与synchronized
关键字的区别
-
锁的获取和释放
synchronized
关键字在代码块或方法上使用时,锁的获取和释放是自动的,由JVM负责管理。ReentrantLock
类需要手动调用lock()
方法获取锁,调用unlock()
方法释放锁。这种手动管理锁的方式提供了更大的灵活性,但也增加了出错的风险。
-
公平性
synchronized
关键字实现的锁是非公平锁,即线程获取锁的顺序不保证是按照请求锁的顺序。ReentrantLock
类可以选择公平锁或非公平锁。公平锁会按照线程请求锁的顺序分配锁,而非公平锁则不保证这一点。
-
锁的粒度
synchronized
关键字只能用于代码块或方法级别的锁。ReentrantLock
类提供了更细粒度的锁控制,可以通过调用lock()
和unlock()
方法来精确控制锁的范围。
-
条件变量
synchronized
关键字不支持条件变量,无法实现复杂的线程等待/通知机制。ReentrantLock
类提供了Condition
接口,支持创建多个条件变量,可以实现复杂的线程等待/通知机制。
在多线程环境下如何选择使用
- 如果是在单线程环境下,或者虽然有多个线程但不会发生竞争条件,使用
synchronized
关键字就可以满足需求。 - 如果是在多线程环境下,并且需要更灵活的锁控制、公平锁、条件变量等特性,推荐使用
ReentrantLock
类。
示例代码
以下是使用ReentrantLock
和synchronized
关键字实现线程安全的计数器的示例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
public synchronized void incrementSynchronized() {
count++;
}
public synchronized int getCountSynchronized() {
return count;
}
public static void main(String[] args) {
LockExample lockExample = new LockExample();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
lockExample.increment();
lockExample.incrementSynchronized();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count using ReentrantLock: " + lockExample.getCount());
System.out.println("Count using synchronized: " + lockExample.getCountSynchronized());
}
}
总结
ReentrantLock
类提供了更灵活的锁机制,适用于需要更细粒度的锁控制、公平锁、条件变量等特性的场景。与synchronized
关键字相比,ReentrantLock
类提供了更多的控制选项,但也增加了出错的风险。在多线程环境下,根据具体需求选择合适的锁机制。