--- /dev/null
+/*
+ * 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();
+ }
+}