对共享资源的访问一般包括两种类型的动作,读和写(修改、删除等会引起资源发生变化的动作),当多个线程同时对某个共享资源进行读取操作时,并不会引起共享资源数据不一致情况的发生(如表3-2所示),因此这个时候如果仍旧让资源的访问互斥,就会显得有些不合情理了,Doug Lea在JDK 1.5版本引入了读写锁类,旨在允许某个特定时刻多线程并发读取共享资源,提高系统性能和访问吞吐量。
可参考: 多线程设计模式: 读写锁分离设计模式
文章目录
1 读写锁的基本使用方法
使用的过程中需要分别派生出“读锁”和“写锁”,在进行共享资源读取操作时,需要使用读锁进行数据同步,在对共享资源进行写操作时,需要使用写锁进行数据一致性的保护
public class ReentrantReadWriteLockDemo1 {
// 定义读写锁
ReadWriteLock lock = new
ReentrantReadWriteLock();
// 读锁
Lock readLock = lock.readLock();
// 写锁
Lock writeLock = lock.writeLock();
// 共享数据
private final LinkedList<String> list = new LinkedList<>();
/**
* 添加数据
*/
public void add(String data) {
writeLock.lock();
try {
list.addLast(data);
} finally {
writeLock.unlock();
}
}
/**
* 删除数据
*
* @return
*/
public String take() {
writeLock.lock();
try {
return list.removeFirst();
} finally {
writeLock.unlock();
}
}
/**
* 使用读锁进行数据同步
*/
public String get(int index) {
readLock.lock();
try {
return list.get(index);
} finally {
readLock.unlock();
}
}
}
- 首先创建了一个ReentrantReadWriteLock锁,然后根据该锁分别创建了读锁和写锁。
- 读锁和写锁都是Lock接口的实现,因此具有Lock接口所定义的所有方法,比如lock()、unlock()等方法。
- 若某个线程获取了写锁进行数据写操作,那么此时其他线程对共享资源的读写操作都会被阻塞直到锁被释放。
- 若某个线程获取了读锁进行数据读操作,那么此时其他线程对共享资源的写操作会进入阻塞直到锁被释放,但如果是其他线程对共享资源进行读操作则不会被阻塞。
2 读写锁的方法
ReadWriteLock接口只有两个方法用于创建读锁和写锁,ReentrantReadWriteLock实现自ReadWriteLock接口并且提供了一些ReadWriteLock监控查询方法
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
ReentrantReadWriteLock实现了ReadWriteLock
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
public ReentrantReadWriteLock.WriteLock writeLock() {
return writerLock;
}
public ReentrantReadWriteLock.ReadLock readLock() {
return readerLock;
}
// 实现了Lock接口,所以具有Lock接口的所有能力
public static class ReadLock implements Lock, java.io.Serializable{
}
// 实现了Lock接口,所以具有Lock接口的所有能力
public static class WriteLock implements Lock, java.io.Serializable{
}
}
ReentrantReadWriteLock、ReadLock以及WriteLock的方法与ReentrantLock十分相似,这里不做介绍,可参考: