一ReentrantReadWriteLock
- 是Lock的另一种实现方式
- 我们知道ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。
- 在实际应用中,对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。
- 读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。
二ReentrantReadWriteLock支持以下功能:
- 支持公平和非公平的获取锁的方式;
- 支持可重入。
- 读线程在获取了读锁后还可以获取读锁;
- 写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
- 允许从写入锁降级为读取锁,但不允许从读取锁升级到写入锁,其实现方式是:
- 先获取写入锁,
- 然后获取读取锁,
- 最后释放写入锁。
- 读取锁和写入锁都支持锁获取期间的中断;
- Condition支持。
- 只有写入锁提供了一个 Conditon 实现;
- 读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。
三案例
package com.feizhou.example.demo;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 使用读写锁,可以实现读写分离锁定,读操作并发进行,写操作锁定单个线程
* <p>
* 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。
* 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
*
* @author
*/
public class Test {
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
for (int i = 0; i < 5; i++) {
new Thread() {
public void run() {
test.get(Thread.currentThread());
}
}.start();
}
Thread.sleep(2000L);
for (int i = 0; i < 5; i++) {
new Thread() {
public void run() {
test.write(Thread.currentThread());
}
}.start();
}
}
/**
* 读操作,用读锁来锁定
*
* @param thread
*/
public void get(Thread thread) {
rwl.readLock().lock();
try {
System.out.println(thread.getName() + "正在进行读操作"+System.currentTimeMillis());
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
}
/**
* 写操作,用写锁来锁定
*
* @param thread
*/
public void write(Thread thread) {
rwl.writeLock().lock();
try {
System.out.println(thread.getName() + "正在进行写操作"+System.currentTimeMillis());
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
}
}
测试
Thread-2正在进行读操作1575289529200
Thread-3正在进行读操作1575289529201
Thread-4正在进行读操作1575289529201
Thread-1正在进行读操作1575289529201
Thread-0正在进行读操作1575289529201
Thread-6正在进行写操作1575289531200
Thread-7正在进行写操作1575289531300
Thread-5正在进行写操作1575289531401
Thread-8正在进行写操作1575289531502
Thread-9正在进行写操作1575289531602