本文目录导读:

我来为你提供几个ReentrantReadWriteLock的实用案例,从基础到进阶。
基础缓存案例
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockCache<K, V> {
private final Map<K, V> cache = new HashMap<>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
// 写入操作 - 使用写锁
public void put(K key, V value) {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 正在写入数据...");
Thread.sleep(100); // 模拟耗时操作
cache.put(key, value);
System.out.println(Thread.currentThread().getName() + " 写入完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwLock.writeLock().unlock();
}
}
// 读取操作 - 使用读锁(可并发)
public V get(K key) {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 正在读取数据...");
Thread.sleep(50);
V value = cache.get(key);
System.out.println(Thread.currentThread().getName() + " 读取完成: " + value);
return value;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
} finally {
rwLock.readLock().unlock();
}
}
// 清空缓存
public void clear() {
rwLock.writeLock().lock();
try {
cache.clear();
} finally {
rwLock.writeLock().unlock();
}
}
// 测试代码
public static void main(String[] args) {
ReadWriteLockCache<String, String> cache = new ReadWriteLockCache<>();
cache.put("key1", "value1");
cache.put("key2", "value2");
// 模拟多个线程读取
for (int i = 0; i < 3; i++) {
new Thread(() -> {
cache.get("key1");
cache.get("key2");
}, "Reader-" + i).start();
}
// 模拟写入线程
new Thread(() -> {
cache.put("key3", "value3");
}, "Writer").start();
}
}
可降级的锁示例
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockDowngradeExample {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private volatile boolean dataReady = false;
private Object data = null;
// 写锁降级为读锁
public void processData() {
rwLock.writeLock().lock();
try {
// 1. 获取写锁,修改数据
System.out.println(Thread.currentThread().getName() + " 获取写锁,更新数据");
data = new Object();
dataReady = true;
// 2. 写锁降级为读锁
rwLock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " 写锁降级为读锁");
} finally {
rwLock.writeLock().unlock(); // 释放写锁,仍持有读锁
}
try {
// 3. 此时持有读锁,可以继续读取数据
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " 持有读锁,读取数据: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwLock.readLock().unlock(); // 释放读锁
}
}
// 错误的降级方式(不推荐)
public void wrongProcessData() {
rwLock.readLock().lock();
try {
// 读锁不能升级为写锁,会导致死锁
rwLock.writeLock().lock(); // 这里会导致死锁
try {
data = new Object();
} finally {
rwLock.writeLock().unlock();
}
} finally {
rwLock.readLock().unlock();
}
}
public static void main(String[] args) {
LockDowngradeExample example = new LockDowngradeExample();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
example.processData();
}, "Thread-" + i).start();
}
}
}
读写锁计数器
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CounterWithReadWriteLock {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private int count = 0;
private final long startTime = System.currentTimeMillis();
// 读取计数
public int getCount() {
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 读取计数: " + count);
return count;
} finally {
rwLock.readLock().unlock();
}
}
// 增加计数
public void increment() {
rwLock.writeLock().lock();
try {
count++;
System.out.println(Thread.currentThread().getName() + " 增加计数到: " + count);
} finally {
rwLock.writeLock().unlock();
}
}
// 获取运行时间
public long getElapsedTime() {
return System.currentTimeMillis() - startTime;
}
public static void main(String[] args) throws InterruptedException {
CounterWithReadWriteLock counter = new CounterWithReadWriteLock();
// 创建多个读取线程
Thread[] readers = new Thread[5];
for (int i = 0; i < readers.length; i++) {
readers[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
counter.getCount();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Reader-" + i);
}
// 创建写入线程
Thread writer = new Thread(() -> {
for (int i = 0; i < 100; i++) {
counter.increment();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Writer");
// 启动所有线程
for (Thread reader : readers) {
reader.start();
}
writer.start();
// 等待完成
for (Thread reader : readers) {
reader.join();
}
writer.join();
System.out.println("最终计数: " + counter.getCount());
System.out.println("运行时间(毫秒): " + counter.getElapsedTime());
}
}
读写锁 vs 普通锁性能对比
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class PerformanceComparison {
private static class SharedData {
private int value = 0;
// 使用ReentrantLock
public static void testWithReentrantLock(int readThreads, int writeThreads, int iterations) {
Lock lock = new ReentrantLock();
SharedData data = new SharedData();
long start = System.currentTimeMillis();
// 创建线程
Thread[] threads = new Thread[readThreads + writeThreads];
// 读取线程
for (int i = 0; i < readThreads; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
lock.lock();
try {
int v = data.value;
} finally {
lock.unlock();
}
}
});
}
// 写入线程
for (int i = 0; i < writeThreads; i++) {
threads[readThreads + i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
lock.lock();
try {
data.value++;
} finally {
lock.unlock();
}
}
});
}
// 启动和等待
for (Thread t : threads) t.start();
for (Thread t : threads) {
try { t.join(); } catch (InterruptedException e) {}
}
System.out.println("ReentrantLock 耗时: " + (System.currentTimeMillis() - start) + "ms");
}
// 使用ReentrantReadWriteLock
public static void testWithReadWriteLock(int readThreads, int writeThreads, int iterations) {
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
SharedData data = new SharedData();
long start = System.currentTimeMillis();
Thread[] threads = new Thread[readThreads + writeThreads];
// 读取线程(使用读锁)
for (int i = 0; i < readThreads; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
rwLock.readLock().lock();
try {
int v = data.value;
} finally {
rwLock.readLock().unlock();
}
}
});
}
// 写入线程(使用写锁)
for (int i = 0; i < writeThreads; i++) {
threads[readThreads + i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
rwLock.writeLock().lock();
try {
data.value++;
} finally {
rwLock.writeLock().unlock();
}
}
});
}
for (Thread t : threads) t.start();
for (Thread t : threads) {
try { t.join(); } catch (InterruptedException e) {}
}
System.out.println("ReentrantReadWriteLock 耗时: " + (System.currentTimeMillis() - start) + "ms");
}
}
public static void main(String[] args) {
System.out.println("=== 读多写少场景 ===");
SharedData.testWithReentrantLock(8, 2, 10000);
SharedData.testWithReadWriteLock(8, 2, 10000);
System.out.println("\n=== 读写均衡场景 ===");
SharedData.testWithReentrantLock(5, 5, 10000);
SharedData.testWithReadWriteLock(5, 5, 10000);
}
}
重要注意事项
public class ReadWriteLockImportantNotes {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); // 公平锁
public void importantNotes() {
// 1. 锁的公平性
System.out.println("公平模式: " + rwLock.isFair());
// 2. 锁的可重入性
rwLock.writeLock().lock();
try {
System.out.println("写锁可重入,当前锁数量: " + rwLock.getWriteHoldCount());
// 写锁内可以再次获取写锁
rwLock.writeLock().lock();
try {
System.out.println("再次获取写锁,数量: " + rwLock.getWriteHoldCount());
} finally {
rwLock.writeLock().unlock();
}
// 写锁降级为读锁
rwLock.readLock().lock();
try {
System.out.println("写锁已降级为读锁");
} finally {
rwLock.readLock().unlock();
}
} finally {
rwLock.writeLock().unlock();
}
// 3. 查询锁状态
System.out.println("是否有等待获取读锁的线程: " + rwLock.hasQueuedThreads());
System.out.println("队列中等待的线程数: " + rwLock.getQueueLength());
}
public static void main(String[] args) {
ReadWriteLockImportantNotes example = new ReadWriteLockImportantNotes();
example.importantNotes();
// 提醒:避免锁升级导致死锁
System.out.println("\n警告:读锁升级为写锁会导致死锁,应该避免!");
}
}
- 读写分离:读锁可多个线程共享,写锁独占
- 锁降级:写锁可以降级为读锁,但读锁不能升级为写锁
- 性能优势:在读多写少的场景下性能更好
- 公平性:可通过构造参数设置公平锁
- 可重入性:支持锁的重入,但要注意控制重入次数
选择建议:
- 读多写少:使用
ReentrantReadWriteLock - 写多读少:使用
ReentrantLock或synchronized - 读写均衡:需要根据具体场景测试决定