新闻资讯
深入并发锁——ReadWriteLock
在并发场景中用于解决线程安全的问题,我们几乎会高频率的使用到独占式锁,通常使用java提供的关键字synchronized(关于synchronized可以看这篇文章)或者concurrents包中实现了Lock接口的ReentrantLock。
它们都是独占式获取锁,也就是在同一时刻只有一个线程能够获取锁。而在一些业务场景中,大部分只是读数据,写数据很少,如果仅仅是读数据的话并不会影响数据正确性(出现脏读),而如果在这种业务场景下,依然使用独占锁的话,很显然这将是出现性能瓶颈的地方。
针对这种读多写少的情况,java还提供了另外一个实现Lock接口的ReentrantReadWriteLock(读写锁)。读写所允许同一时刻被多个读线程访问,但是在写线程访问时,所有的读线程和其他的写线程都会被阻塞。
1、ReadWriteLock接口
ReadWriteLock,顾明思义,读写锁在读的时候,上读锁,在写的时候,上写锁,这样就很巧妙的解决synchronized的一个性能问题:读与读之间互斥。
ReadWriteLock也是一个接口,原型如下:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
} 复制代码
该接口只有两个方法,读锁和写锁。
也就是说,我们在写文件的时候,可以将读和写分开,分成2个锁来分配给线程,从而可以做到读和读互不影响,读和写互斥,写和写互斥,提高读写文件的效率。
2、ReentrantReadWriteLock应用
下面的实例参考《Java并发编程的艺术》,使用读写锁实现一个缓存。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache {
static Map<String,Object> map = new HashMap<String, Object>();
static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
public static final Object getByKey(String key){ readLock.lock();
try{ return map.get(key);
}finally{ readLock.unlock();
}
}
public static final Object getMap(){ readLock.lock();
try{ return map;
}finally{ readLock.unlock();
}
}
public static final Object put(String key,Object value){
writeLock.lock();
try{ return map.put(key, value);
}finally{
writeLock.unlock();
}
}
public static final Object remove(String key){
writeLock.lock();
try{ return map.remove(key);
}finally{
writeLock.unlock();
}
}
public static final void clear(){
writeLock.lock();
try{
map.clear();
}finally{
writeLock.unlock();
}
}
public static void main(String[] args) {
List<Thread> threadList = new ArrayList<Thread>(); for(int i =0;i<6;i++){
Thread thread = new PutThread();
threadList.add(thread);
} for(Thread thread : threadList){
thread.start();
}
put("ji","ji");
System.out.println(getMap());
}
private static class PutThread extends Thread{
public void run(){
put(Thread.currentThread().getName(),Thread.currentThread().getName());
}
}
}
3、读写锁的锁降级
读写锁支持锁降级,遵循按照获取写锁,获取读锁再释放写锁的次序,写锁能够降级成为读锁,不支持锁升级,关于锁降级下面的示例代码摘自ReentrantWriteReadLock源码中:
void processCachedData() {
rwl.readLock().lock(); if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did. if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read }
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
回复列表