(no commit message)
[utils] / support / general / src / main / java / org / wamblee / concurrency / ReadWriteLock.java
diff --git a/support/general/src/main/java/org/wamblee/concurrency/ReadWriteLock.java b/support/general/src/main/java/org/wamblee/concurrency/ReadWriteLock.java
new file mode 100644 (file)
index 0000000..e765816
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2005 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+package org.wamblee.concurrency;
+
+import java.util.HashSet;
+
+
+/**
+ * Read-write lock for allowing multiple concurrent readers or at most one
+ * writer. This implementation does not aim for high performance but for
+ * robustness and simplicity. Users of this class should not synchronize on
+ * objects of this class.
+ */
+public class ReadWriteLock {
+    /**
+     * Sets containing the references to the threads that are currently
+     * reading. This administration is useful to check that the lock has
+     * already been  acquired before it is release. This check adds robustness
+     * to the application.
+     */
+    private HashSet<Thread> _readers;
+
+    /**
+     * The thread that has acquired the lock for writing or null if no such
+     * thread exists currently.
+     */
+    private Thread _writer;
+
+    /**
+     * Constructs read-write lock.
+     */
+    public ReadWriteLock() {
+        _readers     = new HashSet<Thread>();
+        _writer      = null;
+    }
+
+    /**
+     * Acquires the lock for reading. This call will block until the lock can
+     * be acquired.
+     *
+     * @throws IllegalStateException Thrown if the read or  write lock is
+     *         already acquired.
+     */
+    public synchronized void acquireRead() {
+        if (_readers.contains(Thread.currentThread())) {
+            throw new IllegalStateException(
+                "Read lock already acquired by current thread: "
+                + Thread.currentThread());
+        }
+
+        if (_writer == Thread.currentThread()) {
+            throw new IllegalStateException(
+                "Trying to acquire the read lock while already holding a write lock: "
+                + Thread.currentThread());
+        }
+
+        while (_writer != null) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                notifyAll();
+            }
+        }
+
+        _readers.add(Thread.currentThread());
+    }
+
+    /**
+     * Releases the lock for reading. Note: This implementation assumes that
+     * the lock has already been acquired for reading previously.
+     *
+     * @throws IllegalStateException Thrown when the lock was not acquired by
+     *         this thread.
+     */
+    public synchronized void releaseRead() {
+        if (!_readers.remove(Thread.currentThread())) {
+            throw new IllegalStateException(
+                "Cannot release read lock because current thread has not acquired it.");
+        }
+
+        if (_readers.size() == 0) {
+            notifyAll();
+        }
+    }
+
+    /**
+     * Acquires the lock for writing. This call will block until the lock has
+     * been acquired.
+     *
+     * @throws IllegalStateException Thrown if the read or write lock is
+     *         already acquired.
+     */
+    public synchronized void acquireWrite() {
+        if (_writer == Thread.currentThread()) {
+            throw new IllegalStateException(
+                "Trying to acquire a write lock while already holding the write lock: "
+                + Thread.currentThread());
+        }
+
+        if (_readers.contains(Thread.currentThread())) {
+            throw new IllegalStateException(
+                "Trying to acquire a write lock while already holding the read lock: "
+                + Thread.currentThread());
+        }
+
+        // wait until there are no more writers and no more
+        // readers 
+        while ((_writer != null) || (_readers.size() > 0)) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                notifyAll();
+            }
+        }
+
+        _writer = Thread.currentThread();
+
+        // notification not necessary since all writers and
+        // readers are now blocked by this thread.
+    }
+
+    /**
+     * Releases the lock for writing.
+     *
+     * @throws IllegalStateException Thrown when the lock was not acquired.
+     */
+    public synchronized void releaseWrite() {
+        if (_writer != Thread.currentThread()) {
+            throw new IllegalStateException(
+                "Cannot release write lock because it was not acquired. ");
+        }
+
+        _writer = null;
+        notifyAll();
+    }
+}