读写锁维护一对锁,一个读锁和一个写锁。读写锁在同一时刻允许多个读线程获取读锁;但是同一时刻只能有一个线程获取到写锁,此时其他读写操作均被阻塞。并发性相比其他排他锁有了很大的提升。
一、读写锁的特性
1、公平性与非公平性选择
支持非公平(默认)和公平的锁获取方式,吞吐量非公平优于公平。
2、重进入
支持重进入,以读写线程为例:读线程在获取读锁能再次获取读锁。而写线程在获取写锁之后,能再次获取写锁,同时也可以获取读锁。
3、锁降级
遵循获取写锁,获取读锁在释放写锁的次序,写锁能降级为读锁。
二、接口与示例
ReadWriteLock仅定义了获取读锁和写锁的两个方法,即eadLock()方法和writeLock()方法,而其实现——ReentrantReadWriteLock,除了接口方法之外,还提供了一些便于外界监控其内部工作状态的方法,如下:
1、int getReadLockCount()
返回当前读锁被获取的次数。
2、int getReadHoldCount()
返回当前线程获取读锁的次数。
3、boolean isWriteLocked()
判断写锁是否被获取。
4、int getWriteHoldCount()
判断当期写锁被获取的次数。
下面是通过缓存展示读写锁的使用方式。
public class SafeCache {
private Map <String ,Object> map = new HashMap<String , Object>();
//读写锁
private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
//读锁
private static Lock rl = rwl.readLock();
//写锁
private static Lock wl = rwl.writeLock();
//获取元素
public final Object get(String key){
rl.lock();
try{
return map.get(key);
}finally{
rl.unlock();
}
}
//插入操作
public final Object put(String key , Object value){
wl.lock();
try{
return map.put(key, value);
}finally{
wl.unlock();
}
}
//清空元素
public void clear(){
wl.lock();
try{
map.clear();
}finally{
wl.unlock();
}
}
}
Cache组合一个非线程安全的HashMap作为缓存的实现,同时使用读写锁的读锁和写锁来保证Cache是线程安全的。在读操作get(String key)方法中,需要获取读锁,这使得并发访问该方法时不会被阻塞。写操作put(String key,Object value)方法和clear()方法,在更新HashMap时必须提前获取写锁,当获取写锁后,其他线程对于读锁和写锁的获取均被阻塞,而只有写锁被释放之后,其他读写操作才能继续。Cache使用读写锁提升读操作的并发性,也保证每次写操作对所有的读写操作的可见性,同时简化了编程方式。
网友评论