读/写锁的实现和应用(高并发状态下的map实现)

来源:互联网 发布:忘羡捏脸数据 编辑:程序博客网 时间:2024/06/05 13:33
程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存)。这就需要一个读/写锁来解决这个问题。

按照上面的叙述,简单的实现出一个读/写锁

public class ReadWriteLock{  private int readers = 0;  private int writers = 0;  private int writeRequests = 0;  public synchronized void lockRead()      throws InterruptedException{      while(writers > 0 || writeRequests > 0){          wait();      }      readers++;  }  public synchronized void unlockRead(){      readers--;      notifyAll();  }  public synchronized void lockWrite()      throws InterruptedException{      writeRequests++;      while(readers > 0 || writers > 0){          wait();      }      writeRequests--;      writers++;  }  public synchronized void unlockWrite()      throws InterruptedException{      writers--;      notifyAll();  }}

 

 

ReadWriteLock类中,读锁和写锁各有一个获取锁和释放锁的方法。

 

可重入的ReadWriteLock的完整实现

下面是完整的ReadWriteLock实现。为了便于代码的阅读与理解,简单对上面的代码做了重构。重构后的代码如下。

public class ReadWriteLock{ private Map<Thread, Integer> readingThreads =     new HashMap<Thread, Integer>(); private int writeAccesses    = 0; private int writeRequests    = 0; private Thread writingThread = null; public synchronized void lockRead()     throws InterruptedException{     Thread callingThread = Thread.currentThread();     while(! canGrantReadAccess(callingThread)){         wait();     }     readingThreads.put(callingThread,         (getReadAccessCount(callingThread) + 1)); } private boolean canGrantReadAccess(Thread callingThread){     if(isWriter(callingThread)) return true;     if(hasWriter()) return false;     if(isReader(callingThread)) return true;     if(hasWriteRequests()) return false;     return true; } public synchronized void unlockRead(){     Thread callingThread = Thread.currentThread();     if(!isReader(callingThread)){         throw new IllegalMonitorStateException(             "Calling Thread does not" +             " hold a read lock on this ReadWriteLock");     }     int accessCount = getReadAccessCount(callingThread);     if(accessCount == 1){         readingThreads.remove(callingThread);     } else {         readingThreads.put(callingThread, (accessCount -1));     }     notifyAll(); } public synchronized void lockWrite()     throws InterruptedException{     writeRequests++;     Thread callingThread = Thread.currentThread();     while(!canGrantWriteAccess(callingThread)){         wait();     }     writeRequests--;     writeAccesses++;     writingThread = callingThread; } public synchronized void unlockWrite()     throws InterruptedException{     if(!isWriter(Thread.currentThread()){     throw new IllegalMonitorStateException(         "Calling Thread does not" +         " hold the write lock on this ReadWriteLock");     }     writeAccesses--;     if(writeAccesses == 0){         writingThread = null;     }     notifyAll(); } private boolean canGrantWriteAccess(Thread callingThread){     if(isOnlyReader(callingThread)) return true;     if(hasReaders()) return false;     if(writingThread == null) return true;     if(!isWriter(callingThread)) return false;     return true; } private int getReadAccessCount(Thread callingThread){     Integer accessCount = readingThreads.get(callingThread);     if(accessCount == null) return 0;     return accessCount.intValue(); } private boolean hasReaders(){     return readingThreads.size() > 0; } private boolean isReader(Thread callingThread){     return readingThreads.get(callingThread) != null; } private boolean isOnlyReader(Thread callingThread){     return readingThreads.size() == 1 &&         readingThreads.get(callingThread) != null; } private boolean hasWriter(){     return writingThread != null; } private boolean isWriter(Thread callingThread){     return writingThread == callingThread; } private boolean hasWriteRequests(){     return this.writeRequests > 0; }}

应用:线程安全并且高并发状态下的map实现

class RWDictionary {    private final Map<String, Data> m = new TreeMap<String, Data>();    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();    private final Lock r = rwl.readLock();    private final Lock w = rwl.writeLock();    public Data get(String key) {        r.lock();        try { return m.get(key); }        finally { r.unlock(); }    }    public String[] allKeys() {        r.lock();        try { return m.keySet().toArray(); }        finally { r.unlock(); }    }    public Data put(String key, Data value) {        w.lock();        try { return m.put(key, value); }        finally { w.unlock(); }    }    public void clear() {        w.lock();        try { m.clear(); }        finally { w.unlock(); }    } }

 

0 0