(no commit message)
[utils] / support / src / org / wamblee / concurrency / ReadWriteLock.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */ 
16 package org.wamblee.concurrency;
17
18 import java.util.HashSet;
19
20
21 /**
22  * Read-write lock for allowing multiple concurrent readers or at most one
23  * writer. This implementation does not aim for high performance but for
24  * robustness and simplicity. Users of this class should not synchronize on
25  * objects of this class.
26  */
27 public class ReadWriteLock {
28     /**
29      * Sets containing the references to the threads that are currently
30      * reading. This administration is useful to check that the lock has
31      * already been  acquired before it is release. This check adds robustness
32      * to the application.
33      */
34     private HashSet<Thread> _readers;
35
36     /**
37      * The thread that has acquired the lock for writing or null if no such
38      * thread exists currently.
39      */
40     private Thread _writer;
41
42     /**
43      * Constructs read-write lock.
44      */
45     public ReadWriteLock() {
46         _readers     = new HashSet<Thread>();
47         _writer      = null;
48     }
49
50     /**
51      * Acquires the lock for reading. This call will block until the lock can
52      * be acquired.
53      *
54      * @throws IllegalStateException Thrown if the read or  write lock is
55      *         already acquired.
56      */
57     public synchronized void acquireRead() {
58         if (_readers.contains(Thread.currentThread())) {
59             throw new IllegalStateException(
60                 "Read lock already acquired by current thread: "
61                 + Thread.currentThread());
62         }
63
64         if (_writer == Thread.currentThread()) {
65             throw new IllegalStateException(
66                 "Trying to acquire the read lock while already holding a write lock: "
67                 + Thread.currentThread());
68         }
69
70         while (_writer != null) {
71             try {
72                 wait();
73             } catch (InterruptedException e) {
74                 notifyAll();
75             }
76         }
77
78         _readers.add(Thread.currentThread());
79     }
80
81     /**
82      * Releases the lock for reading. Note: This implementation assumes that
83      * the lock has already been acquired for reading previously.
84      *
85      * @throws IllegalStateException Thrown when the lock was not acquired by
86      *         this thread.
87      */
88     public synchronized void releaseRead() {
89         if (!_readers.remove(Thread.currentThread())) {
90             throw new IllegalStateException(
91                 "Cannot release read lock because current thread has not acquired it.");
92         }
93
94         if (_readers.size() == 0) {
95             notifyAll();
96         }
97     }
98
99     /**
100      * Acquires the lock for writing. This call will block until the lock has
101      * been acquired.
102      *
103      * @throws IllegalStateException Thrown if the read or write lock is
104      *         already acquired.
105      */
106     public synchronized void acquireWrite() {
107         if (_writer == Thread.currentThread()) {
108             throw new IllegalStateException(
109                 "Trying to acquire a write lock while already holding the write lock: "
110                 + Thread.currentThread());
111         }
112
113         if (_readers.contains(Thread.currentThread())) {
114             throw new IllegalStateException(
115                 "Trying to acquire a write lock while already holding the read lock: "
116                 + Thread.currentThread());
117         }
118
119         // wait until there are no more writers and no more
120         // readers 
121         while ((_writer != null) || (_readers.size() > 0)) {
122             try {
123                 wait();
124             } catch (InterruptedException e) {
125                 notifyAll();
126             }
127         }
128
129         _writer = Thread.currentThread();
130
131         // notification not necessary since all writers and
132         // readers are now blocked by this thread.
133     }
134
135     /**
136      * Releases the lock for writing.
137      *
138      * @throws IllegalStateException Thrown when the lock was not acquired.
139      */
140     public synchronized void releaseWrite() {
141         if (_writer != Thread.currentThread()) {
142             throw new IllegalStateException(
143                 "Cannot release write lock because it was not acquired. ");
144         }
145
146         _writer = null;
147         notifyAll();
148     }
149 }