首页 > 代码库 > 读写锁

读写锁

锁维护了一对锁,一个读锁和一个写,通分离读锁和写锁,使得并性相比一般的排他有了很大提升 

一般情况下,的性能都会比排它好,因大多数是多于写的。在多于写的情况下,提供比排它更好的并性和吞吐量。Java包提供实现是ReentrantReadWriteLock,它提供的特性如表所示。 

技术分享

的接口与示例

ReadWriteLock读锁和写的两个方法,即readLock()方法和writeLock()方法,而其实现——ReentrantReadWriteLock,除了接口方法之外,提供了一些便于外界控其内部工作状的方法,些方法以及描述如表所示 

技术分享

一个的使用方式的缓存示例:

public class Cache {
  static Map<String, Object> map = new HashMap<String, Object>();
  static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  static Lock r = rwl.readLock();
  static Lock w = rwl.writeLock();
  // 获取一个key对应的value
  public static final Object get(String key) {
    r.lock();
    try {
      return map.get(key);
    } finally {
      r.unlock();
    }
  }
  // 设置key对应的value,并返回旧的value   public static final Object put(String key, Object value) {     w.lock();     try {       return map.put(key, value);     } finally {       w.unlock();     }   }
  // 清空所有的内容   public static final void clear() {     w.lock();     try {       map.clear();     } finally {       w.unlock();     }   } }

 上述示例中,Cache合一个非线程安全的HashMap为缓存的实现,同使用的读锁和写来保Cache线程安全的。在操作get(String key)方法中,需要读锁使得并发访问该方法不会被阻塞。写操作put(String key,Object value)方法和clear()方法,在更新HashMap提前取写,当取写后,其他线读锁和写取均被阻塞,而只有写放之后,其他写操作才能继续Cache使用提升操作的并性,也保证每次写操作所有的写操作的可性,同时简化了程方式。 


实现分析 (以下没有特别说均可认为ReentrantReadWriteLock ):

  1. 写状设计
  2. 取与释放
  3. 读锁取与

1.写状设计

自定同步器来实现同步功能,而写状就是其同步器的同步状。回想ReentrantLock中自定同步器的实现,同步状表示被一个线程重复取的次数,而的自定同步器需要在同步状(一个整型量)上维护多个读线程和一个写线程的状态,使得设计为读锁实现的关

 如果在一个整型量上维护多种状,就一定需要按位切割使用量,量切分成了两个部分,高16位表示,低16位表示写,划分方式如5-8所示。
 
技术分享

当前同步状表示一个线程已经获取了写,且重入了两次,同连续获取了两次读锁。 是通位运算来确定和写各自的状态。当前同步状态值为S,写状等于S&0x0000FFFF(将高16位全部抹去),等于S>>>16(无符号右移16位)。当写状增加1,等于S+1,当增加1,等于S+(1<<16),也就是S+0x00010000


 2.取与放 

是一个支持重入的排它。如果当前线程已经获取了写增加写状

//ReentrantReadWriteLock的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
  Thread current = Thread.currentThread();
  int c = getState();
  int w = exclusiveCount(c);
  if (c != 0) {
    // 存在读锁或者当前获取线程不是已经获取写锁的线程
    if (w == 0 || current != getExclusiveOwnerThread())
      return false;
    if (w + exclusiveCount(acquires) > MAX_COUNT)
      throw new Error("Maximum lock count exceeded");
    setState(c + acquires);
    return true;
  }
  if (writerShouldBlock()
|| !compareAndSetState(c, c + acquires)) {     return false;   }
  setExclusiveOwnerThread(current);   
return true; }

 

 方法除了重入条件(当前线为获取了写线程)之外,增加了一个读锁是否存在的判断。 

放与ReentrantLock程基本似,每次放均减少写状,当写状态为0表示写已被放,从而等待的线程能够继续访问读,同前次写线程的修改续读线程可

3.读锁取与

 

 



 

读写锁