ReentrantReadWriteLock
是Java并发包提供的一个读写锁实现,它允许多个线程同时读取共享资源,但在写入时只允许一个线程进行,从而提高读取操作的并发性。这种锁的设计是为了在读多写少的场景下提供更好的性能。
特性:
-
读锁(共享锁):
多个线程可以同时持有读锁,只要没有写锁被持有。 -
写锁(独占锁):
写锁是独占的,一次只能被一个线程持有。当有线程持有写锁时,任何的读锁和写锁请求都会被阻塞。 -
重入性:
ReentrantReadWriteLock
是可重入的,允许线程在持有锁的情况下重新进入相同的锁。 -
公平性:
ReentrantReadWriteLock
提供了公平性和非公平性两种构造方法。在公平模式下,等待时间最长的线程将获得锁。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class SharedResource {
private int data = 0;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public int readData() {
lock.readLock().lock();
try {
// 读取共享资源
return data;
} finally {
lock.readLock().unlock();
}
}
public void writeData(int newData) {
lock.writeLock().lock();
try {
// 写入共享资源
data = newData;
} finally {
lock.writeLock().unlock();
}
}
}
public class ReentrantReadWriteLockExample {
public static void main(String[] args) {
SharedResource sharedResource = new SharedResource();
// 多个线程可以同时读取共享资源
new Thread(() -> {
System.out.println("Read data: " + sharedResource.readData());
}).start();
new Thread(() -> {
System.out.println("Read data: " + sharedResource.readData());
}).start();
// 一次只能有一个线程写入共享资源
new Thread(() -> {
sharedResource.writeData(42);
}).start();
}
}
在ReentrantReadWriteLock
中,读锁是共享的,而写锁是独占的。如果一个线程(比如线程A)持有读锁,其他线程(比如线程B)仍然可以获取读锁,因为读锁是共享的,多个线程可以同时持有读锁。
但是,当一个线程(比如线程A)持有读锁时,其他线程(包括线程B)如果要获取写锁,它们会被阻塞,因为写锁是独占的。在ReentrantReadWriteLock
的设计中,写锁和读锁之间存在互斥关系,即当有线程持有写锁时,其他线程无法同时持有读锁或写锁。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReentrantReadWriteLockExample {
private static final ReadWriteLock lock = new ReentrantReadWriteLock();
public static void main(String[] args) {
// 线程A持有读锁
new Thread(() -> {
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " acquired read lock.");
// 模拟线程A一直持有读锁
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}, "Thread A").start();
// 线程B尝试获取写锁
new Thread(() -> {
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " acquired write lock.");
} finally {
lock.writeLock().unlock();
}
}, "Thread B").start();
}
}