介绍
在 Java 的并发编程中,锁是保证线程安全的重要机制。ReentrantLock 是 Java 提供的一种可重入锁,提供了比 synchronized 更多的灵活性和特性。
ReentrantLock 的作用
ReentrantLock 可以用于多个线程互斥地访问共享资源,保证线程安全。
ReentrantLock 类
ReentrantLock 类是 ReentrantLock 的主要实现类,提供了获取锁、释放锁、获取锁状态等功能。
获取锁
ReentrantLock 的获取和释放锁的方式与 synchronized 不同,ReentrantLock 可以控制锁的公平性、支持尝试获取锁、支持中断等特性。
ReentrantLock 的获取和释放
获取和释放锁的方式如下:
ReentrantLock lock = new ReentrantLock();
lock.lock(); // 获取锁
try {
// 访问共享资源
} finally {
lock.unlock(); // 释放锁
}
公平锁和非公平锁
ReentrantLock 提供了公平锁和非公平锁两种获取锁的方式。
公平锁:按照线程请求锁的时间顺序依次获取锁,保证所有线程公平获取锁。但是,公平锁的性能稍低。
ReentrantLock lock = new ReentrantLock(true); // 创建公平锁
非公平锁:不保证获取锁的顺序,可能会导致某些线程一直无法获取锁。但是,非公平锁的性能更高。
ReentrantLock lock = new ReentrantLock(false); // 创建非公平锁
tryLock 方法
ReentrantLock 还提供了一个 tryLock 方法,用于尝试获取锁。如果锁已经被其他线程持有,则该方法返回 false。
ReentrantLock lock = new ReentrantLock();
if (lock.tryLock()) { // 尝试获取锁
try {
// 访问共享资源
} finally {
lock.unlock(); // 释放锁
}
} else {
// 锁已经被其他线程持有
}
锁的状态
ReentrantLock 提供了一些方法,用于获取锁的状态和等待队列。
锁的状态和等待队列
ReentrantLock 的 getState 方法可以获取当前锁的状态。
ReentrantLock lock = new ReentrantLock();
int state = lock.getState(); // 获取锁的状态
ReentrantLock 还提供了 getQueueLength 和 hasQueuedThreads 方法,用于获取等待队列的长度和判断是否有线程在等待锁。
ReentrantLock lock = new ReentrantLock();
int queueLength = lock.getQueueLength(); // 获取等待队列的长度
boolean hasQueuedThreads = lock.hasQueuedThreads(); // 判断是否有线程在等待锁
Condition 接口
ReentrantLock 还提供了 Condition 接口,用于实现线程之间的协作。Condition 接口可以通过 await、signal 和 signalAll 方法实现等待、唤醒和广播操作。
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
// 线程等待
condition.await();
// 线程唤醒
condition.signal();
// 广播唤醒等待的线程
condition.signalAll();
} finally {
lock.unlock();
}
性能优化
ReentrantLock 提供了一些特性,用于优化锁的性能和可伸缩性。其中包括偏向锁、轻量级锁、自旋锁等。
优化 ReentrantLock 的使用
ReentrantLock 的性能优化方法如下:
- 避免无谓的加锁和解锁操作
- 使用 tryLock 方法尝试获取锁,避免线程阻塞
- 使用公平锁可以保证所有线程公平获取锁,但是性能会稍低
- 避免使用锁粗粒度化,尽可能使用细粒度锁
偏向锁
偏向锁是一种优化锁性能的机制,用于避免多个线程竞争同一个锁。当只有一个线程访问锁时,偏向锁会将锁的状态记录到线程的栈帧中,避免多个线程竞争锁。
ReentrantLock lock = new ReentrantLock();
lock.lock(); // 获取锁
try {
// 访问共享资源
} finally {
lock.unlock(); // 释放锁
}
当有其他线程竞争锁时,偏向锁会自动撤销,转换为轻量级锁或重量级锁。
轻量级锁
轻量级锁是一种减少线程阻塞的锁机制。当只有一个线程访问锁时,轻量级锁可以避免线程阻塞,提高程序性能。当有其他线程竞争锁时,轻量级锁会自动撤销,转换为重量级锁。
自旋锁
自旋锁是一种优化锁的机制,用于避免线程阻塞,提高程序性能。当有其他线程竞争锁时,自旋锁会让线程自旋等待锁的释放,避免线程阻塞。
扩展
ReentrantLock 还提供了一些其他特性,包括 ReentrantReadWriteLock 类和 StampedLock 类。
ReentrantReadWriteLock 类
ReentrantReadWriteLock 类是 ReentrantLock 的另一种实现,提供了读写锁的机制。读写锁可以允许多个线程同时读取共享资源,但是只允许一个线程写入共享资源。
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock(); // 获取读锁
try {
// 读取共享资源
} finally {
rwLock.readLock().unlock(); // 释放读锁
}
rwLock.writeLock().lock(); // 获取写锁
try {
// 写入共享资源
} finally {
rwLock.writeLock().unlock(); // 释放写锁
}
StampedLock 类
StampedLock 类是 Java 8 新增的一种乐观读锁机制,提供了更高的并发性和可伸缩性。StampedLock 可以允许多个线程同时读取共享资源,但是只允许一个线程写入共享资源。
StampedLock stampLock = new StampedLock();
long stamp = stampLock.readLock();
总结
ReentrantLock 是 Java 提供的一种可重入锁,提供了比 synchronized 更多的灵活性和特性。ReentrantLock 可以用于多个线程互斥地访问共享资源,保证线程安全。ReentrantLock 的获取和释放锁的方式与 synchronized 不同,ReentrantLock 可以控制锁的公平性、支持尝试获取锁、支持中断等特性。ReentrantLock 还提供了一些方法,用于获取锁的状态和等待队列。ReentrantLock 的性能优化方法包括避免无谓的加锁和解锁操作、使用 tryLock 方法尝试获取锁、使用公平锁可以保证所有线程公平获取锁、避免使用锁粗粒度化,尽可能使用细粒度锁。ReentrantLock 还提供了一些其他特性,包括 ReentrantReadWriteLock 类
文章评论