ReentrantLock
是一种可重入互斥锁,它提供了与 synchronized
相同的基本行为和语义,但功能更加强大。其特点包括:
ReentrantLock
配合 Condition
接口提供了比 Object
的 wait()
、notify()
和 notifyAll()
方法更强大的等待/通知机制。import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private int count;
public void add(int n) {
lock.lock();
try {
count += n;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
for (int i = 0; i < 10; i++) {
new Thread(() -> counter.add(1)).start();
}
}
}
ReentrantReadWriteLock
是一种读写锁,允许多个读线程同时访问,但只允许一个写线程访问,或者阻塞所有的读写线程。这种锁的设计可以提高性能,特别是在数据结构中,读操作的数量远远超过写操作的情况下。
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Counter {
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
private int count;
public int getCount() {
r.lock();
try {
return count;
} finally {
r.unlock();
}
}
public void inc() {
w.lock();
try {
count++;
} finally {
w.unlock();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
for (int i = 0; i < 10; i++) {
new Thread(() -> counter.inc()).start();
}
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(counter.getCount())).start();
}
}
}
ReentrantLock
是一个互斥锁,同一时间只有一个线程可以持有锁。ReentrantReadWriteLock
是一个读写锁,允许多个读线程同时访问,但写线程独占访问。ReentrantLock
适用于读写操作频繁且写操作较多的场景。ReentrantReadWriteLock
适用于读操作远多于写操作的场景,可以显著提高并发性能。ReentrantLock
提供了更多的功能,如可中断的锁定、尝试锁定、条件变量等。ReentrantReadWriteLock
提供了读锁和写锁,支持锁降级等高级功能。假设有一个共享的数据结构,读操作远多于写操作。使用 ReentrantReadWriteLock
可以显著提高并发性能,因为多个读线程可以同时访问数据,而写线程则独占访问。以下是一个具体的例子:
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CachedData {
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private Object data;
private boolean cacheValid;
public void processCachedData() {
rwl.readLock().lock();
try {
if (!cacheValid) {
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (!cacheValid) {
data = fetchDataFromDatabase();
cacheValid = true;
}
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock();
}
}
use(data);
} finally {
rwl.readLock().unlock();
}
}
private Object fetchDataFromDatabase() {
// 模拟从数据库获取数据
return new Object();
}
private void use(Object data) {
// 模拟使用数据
System.out.println("使用数据: " + data);
}
public static void main(String[] args) {
CachedData cachedData = new CachedData();
for (int i = 0; i < 10; i++) {
new Thread(() -> cachedData.processCachedData()).start();
}
}
}
在这个例子中,processCachedData
方法首先尝试获取读锁。如果缓存无效,它会释放读锁并获取写锁来更新缓存。更新完成后,它会进行写锁到读锁的降级,允许其他线程并发读取。
通过这种方式,ReentrantReadWriteLock
可以在确保数据一致性的同时,提高多线程环境下的性能。