diff src/EDU/oswego/cs/dl/util/concurrent/ReentrantWriterPreferenceReadWriteLock.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/EDU/oswego/cs/dl/util/concurrent/ReentrantWriterPreferenceReadWriteLock.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,160 @@
+/*
+  File: ReentrantWriterPreferenceReadWriteLock.java
+
+  Originally written by Doug Lea and released into the public domain.
+  This may be used for any purposes whatsoever without acknowledgment.
+  Thanks for the assistance and support of Sun Microsystems Labs,
+  and everyone contributing, testing, and using this code.
+
+  History:
+  Date       Who                What
+  26aug1998  dl                 Create public version
+   7sep2000  dl                 Readers are now also reentrant
+  19jan2001  dl                 Allow read->write upgrades if the only reader 
+  10dec2002  dl                 Throw IllegalStateException on extra release
+*/
+
+package EDU.oswego.cs.dl.util.concurrent;
+import java.util.*;
+
+/** 
+ * A writer-preference ReadWriteLock that allows both readers and 
+ * writers to reacquire
+ * read or write locks in the style of a ReentrantLock.
+ * Readers are not allowed until all write locks held by
+ * the writing thread have been released.
+ * Among other applications, reentrancy can be useful when
+ * write locks are held during calls or callbacks to methods that perform
+ * reads under read locks.
+ * <p>
+ * <b>Sample usage</b>. Here is a code sketch showing how to exploit
+ * reentrancy to perform lock downgrading after updating a cache:
+ * <pre>
+ * class CachedData {
+ *   Object data;
+ *   volatile boolean cacheValid;
+ *   ReentrantWriterPreferenceReadWriteLock rwl = ...
+ *
+ *   void processCachedData() {
+ *     rwl.readLock().acquire();
+ *     if (!cacheValid) {
+ *
+ *        // upgrade lock:
+ *        rwl.readLock().release();   // must release first to obtain writelock
+ *        rwl.writeLock().acquire();
+ *        if (!cacheValid) { // recheck
+ *          data = ...
+ *          cacheValid = true;
+ *        }
+ *        // downgrade lock
+ *        rwl.readLock().acquire();  // reacquire read without giving up lock
+ *        rwl.writeLock().release(); // release write, still hold read
+ *     }
+ *
+ *     use(data);
+ *     rwl.readLock().release();
+ *   }
+ * }
+ * </pre>
+ *
+ * 
+ * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
+ * @see ReentrantLock
+ **/
+
+public class ReentrantWriterPreferenceReadWriteLock extends WriterPreferenceReadWriteLock {
+
+  /** Number of acquires on write lock by activeWriter_ thread **/
+  protected long writeHolds_ = 0;  
+
+  /** Number of acquires on read lock by any reader thread **/
+  protected HashMap readers_ = new HashMap();
+
+  /** cache/reuse the special Integer value one to speed up readlocks **/
+  protected static final Integer IONE = new Integer(1);
+
+
+  protected boolean allowReader() {
+    return (activeWriter_ == null && waitingWriters_ == 0) ||
+      activeWriter_ == Thread.currentThread();
+  }
+
+  protected synchronized boolean startRead() {
+    Thread t = Thread.currentThread();
+    Object c = readers_.get(t);
+    if (c != null) { // already held -- just increment hold count
+      readers_.put(t, new Integer(((Integer)(c)).intValue()+1));
+      ++activeReaders_;
+      return true;
+    }
+    else if (allowReader()) {
+      readers_.put(t, IONE);
+      ++activeReaders_;
+      return true;
+    }
+    else
+      return false;
+  }
+
+  protected synchronized boolean startWrite() {
+    if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
+      ++writeHolds_;
+      return true;
+    }
+    else if (writeHolds_ == 0) {
+      if (activeReaders_ == 0 || 
+          (readers_.size() == 1 && 
+           readers_.get(Thread.currentThread()) != null)) {
+        activeWriter_ = Thread.currentThread();
+        writeHolds_ = 1;
+        return true;
+      }
+      else
+        return false;
+    }
+    else
+      return false;
+  }
+
+
+  protected synchronized Signaller endRead() {
+    Thread t = Thread.currentThread();
+    Object c = readers_.get(t);
+    if (c == null)
+      throw new IllegalStateException();
+    --activeReaders_;
+    if (c != IONE) { // more than one hold; decrement count
+      int h = ((Integer)(c)).intValue()-1;
+      Integer ih = (h == 1)? IONE : new Integer(h);
+      readers_.put(t, ih);
+      return null;
+    }
+    else {
+      readers_.remove(t);
+    
+      if (writeHolds_ > 0) // a write lock is still held by current thread
+        return null;
+      else if (activeReaders_ == 0 && waitingWriters_ > 0)
+        return writerLock_;
+      else
+        return null;
+    }
+  }
+
+  protected synchronized Signaller endWrite() {
+    --writeHolds_;
+    if (writeHolds_ > 0)   // still being held
+      return null;
+    else {
+      activeWriter_ = null;
+      if (waitingReaders_ > 0 && allowReader())
+        return readerLock_;
+      else if (waitingWriters_ > 0)
+        return writerLock_;
+      else
+        return null;
+    }
+  }
+
+}
+