- 写锁:独占锁,一把锁只能被一个线程获得。当一个线程获取写锁后,其他请求读锁和写锁的线程必须等待。
- 读锁:共享锁,没有线程获取写锁的情况下,多个线程可以同时持有读锁。如果己经有线程持有写锁,则其他线程请求获取该读锁会被阻塞
1 使用场合
锁降级的应用场合主要集中在那些需要对共享资源进行更新后立即进行频繁读取,且在这期间不需要再次修改的多线程编程场景。
比如 缓存更新与读取: 在缓存系统中,一个线程可能需要更新缓存内容(需要写锁保护以防止数据不一致)。一旦更新完成,接下来很可能就是一系列对该缓存项的读取操作。此时,如果支持锁降级,线程可以降级为读锁,允许其他线程也进行读取,提高缓存的访问效率。
锁降级适用于任何需要在短暂的写操作后进行长期或频繁读取的场景,它可以减少不必要的独占锁时间,提高系统的并发性能。
2 代码示例
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyReentrantReadWriteLock {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void writeAndThenRead() {
System.out.println("Thread " + Thread.currentThread().getName() + " is trying writing.");
// 获取写锁
lock.writeLock().lock();
try {
System.out.println("Thread " + Thread.currentThread().getName() + " is writing.");
// 模拟写操作
// ...
Thread.sleep(2000);
// 锁降级:在持有写锁的情况下,尝试获取读锁并释放写锁
lock.readLock().lock();
lock.writeLock().unlock(); // 释放写锁,完成降级
System.out.println("Thread " + Thread.currentThread().getName() + " is still reading after downgrade.");
Thread.sleep(10000);
// 模拟读操作
System.out.println("Thread " + Thread.currentThread().getName() + " is still reading after downgrade.");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 确保最终读锁被释放
lock.readLock().unlock();
System.out.println("Thread " + Thread.currentThread().getName() + " finished reading.");
}
}
public void tryWirte() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Thread " + Thread.currentThread().getName() + " is trying writing.");
// 获取写锁
lock.writeLock().lock();
try {
System.out.println("Thread " + Thread.currentThread().getName() + " is writing.");
} finally {
// 确保最终写锁被释放
lock.writeLock().unlock();
System.out.println("Thread " + Thread.currentThread().getName() + " finished writing.");
}
}
public void tryRead() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Thread " + Thread.currentThread().getName() + " is trying reading.");
// 获取读锁
lock.readLock().lock();
try {
System.out.println("Thread " + Thread.currentThread().getName() + " is reading.");
} finally {
// 确保最终读锁被释放
lock.readLock().unlock();
System.out.println("Thread " + Thread.currentThread().getName() + " finished reading.");
}
}
public static void main(String[] args) throws InterruptedException {
MyReentrantReadWriteLock demo = new MyReentrantReadWriteLock();
Thread writerReaderThread = new Thread(() -> demo.writeAndThenRead(), "Writer-Reader Thread");
Thread writerThread = new Thread(() -> demo.tryWirte(),"Writer Thread");
Thread readerThread = new Thread(() -> demo.tryRead(),"Reader Thread");
writerReaderThread.start();
// readerThread.start();
// writerThread.start();
}
}
当发生降级后, Writer-Reader Thread的写锁降级为读锁, 这时候
(1) 写锁是独占的
有读锁时, 不能允许获取写锁
因此将writerThread.start();
取消注释, 运行主程序后, 结果是
Thread Writer-Reader Thread is trying writing.
Thread Writer-Reader Thread is writing.
Thread Writer Thread is trying writing.
Thread Writer-Reader Thread is still reading after downgrade.
Thread Writer-Reader Thread is still reading after downgrade.
Thread Writer-Reader Thread finished reading.
Thread Writer Thread is writing.
Thread Writer Thread finished writing.
等待Writer-Reader Thread释放读锁之后Writer Thread才获得写锁
(2) 读锁可以共享
有读锁时, 允许其他读锁
因此将readerThread.start();
取消注释, 运行主程序后, 结果是
Thread Writer-Reader Thread is trying writing.
Thread Writer-Reader Thread is writing.
Thread Reader Thread is trying reading.
Thread Writer-Reader Thread is still reading after downgrade.
Thread Reader Thread is reading.
Thread Reader Thread finished reading.
Thread Writer-Reader Thread is still reading after downgrade.
Thread Writer-Reader Thread finished reading.
等待Writer-Reader Thread锁降级之后Reader Thread就能获得读锁了