comparison src/EDU/oswego/cs/dl/util/concurrent/WriterPreferenceReadWriteLock.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
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /*
2 File: WriterPreferenceReadWriteLock.java
3
4 Originally written by Doug Lea and released into the public domain.
5 This may be used for any purposes whatsoever without acknowledgment.
6 Thanks for the assistance and support of Sun Microsystems Labs,
7 and everyone contributing, testing, and using this code.
8
9 History:
10 Date Who What
11 11Jun1998 dl Create public version
12 5Aug1998 dl replaced int counters with longs
13 25aug1998 dl record writer thread
14 3May1999 dl add notifications on interrupt/timeout
15
16 */
17
18 package EDU.oswego.cs.dl.util.concurrent;
19
20 /**
21 * A ReadWriteLock that prefers waiting writers over
22 * waiting readers when there is contention. This class
23 * is adapted from the versions described in CPJ, improving
24 * on the ones there a bit by segregating reader and writer
25 * wait queues, which is typically more efficient.
26 * <p>
27 * The locks are <em>NOT</em> reentrant. In particular,
28 * even though it may appear to usually work OK,
29 * a thread holding a read lock should not attempt to
30 * re-acquire it. Doing so risks lockouts when there are
31 * also waiting writers.
32 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
33 **/
34
35 public class WriterPreferenceReadWriteLock implements ReadWriteLock {
36
37 protected long activeReaders_ = 0;
38 protected Thread activeWriter_ = null;
39 protected long waitingReaders_ = 0;
40 protected long waitingWriters_ = 0;
41
42
43 protected final ReaderLock readerLock_ = new ReaderLock();
44 protected final WriterLock writerLock_ = new WriterLock();
45
46 public Sync writeLock() { return writerLock_; }
47 public Sync readLock() { return readerLock_; }
48
49 /*
50 A bunch of small synchronized methods are needed
51 to allow communication from the Lock objects
52 back to this object, that serves as controller
53 */
54
55
56 protected synchronized void cancelledWaitingReader() { --waitingReaders_; }
57 protected synchronized void cancelledWaitingWriter() { --waitingWriters_; }
58
59
60 /** Override this method to change to reader preference **/
61 protected boolean allowReader() {
62 return activeWriter_ == null && waitingWriters_ == 0;
63 }
64
65
66 protected synchronized boolean startRead() {
67 boolean allowRead = allowReader();
68 if (allowRead) ++activeReaders_;
69 return allowRead;
70 }
71
72 protected synchronized boolean startWrite() {
73
74 // The allowWrite expression cannot be modified without
75 // also changing startWrite, so is hard-wired
76
77 boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);
78 if (allowWrite) activeWriter_ = Thread.currentThread();
79 return allowWrite;
80 }
81
82
83 /*
84 Each of these variants is needed to maintain atomicity
85 of wait counts during wait loops. They could be
86 made faster by manually inlining each other. We hope that
87 compilers do this for us though.
88 */
89
90 protected synchronized boolean startReadFromNewReader() {
91 boolean pass = startRead();
92 if (!pass) ++waitingReaders_;
93 return pass;
94 }
95
96 protected synchronized boolean startWriteFromNewWriter() {
97 boolean pass = startWrite();
98 if (!pass) ++waitingWriters_;
99 return pass;
100 }
101
102 protected synchronized boolean startReadFromWaitingReader() {
103 boolean pass = startRead();
104 if (pass) --waitingReaders_;
105 return pass;
106 }
107
108 protected synchronized boolean startWriteFromWaitingWriter() {
109 boolean pass = startWrite();
110 if (pass) --waitingWriters_;
111 return pass;
112 }
113
114 /**
115 * Called upon termination of a read.
116 * Returns the object to signal to wake up a waiter, or null if no such
117 **/
118 protected synchronized Signaller endRead() {
119 if (--activeReaders_ == 0 && waitingWriters_ > 0)
120 return writerLock_;
121 else
122 return null;
123 }
124
125
126 /**
127 * Called upon termination of a write.
128 * Returns the object to signal to wake up a waiter, or null if no such
129 **/
130 protected synchronized Signaller endWrite() {
131 activeWriter_ = null;
132 if (waitingReaders_ > 0 && allowReader())
133 return readerLock_;
134 else if (waitingWriters_ > 0)
135 return writerLock_;
136 else
137 return null;
138 }
139
140
141 /**
142 * Reader and Writer requests are maintained in two different
143 * wait sets, by two different objects. These objects do not
144 * know whether the wait sets need notification since they
145 * don't know preference rules. So, each supports a
146 * method that can be selected by main controlling object
147 * to perform the notifications. This base class simplifies mechanics.
148 **/
149
150 protected abstract class Signaller { // base for ReaderLock and WriterLock
151 abstract void signalWaiters();
152 }
153
154 protected class ReaderLock extends Signaller implements Sync {
155
156 public void acquire() throws InterruptedException {
157 if (Thread.interrupted()) throw new InterruptedException();
158 InterruptedException ie = null;
159 synchronized(this) {
160 if (!startReadFromNewReader()) {
161 for (;;) {
162 try {
163 ReaderLock.this.wait();
164 if (startReadFromWaitingReader())
165 return;
166 }
167 catch(InterruptedException ex){
168 cancelledWaitingReader();
169 ie = ex;
170 break;
171 }
172 }
173 }
174 }
175 if (ie != null) {
176 // fall through outside synch on interrupt.
177 // This notification is not really needed here,
178 // but may be in plausible subclasses
179 writerLock_.signalWaiters();
180 throw ie;
181 }
182 }
183
184
185 public void release() {
186 Signaller s = endRead();
187 if (s != null) s.signalWaiters();
188 }
189
190
191 synchronized void signalWaiters() { ReaderLock.this.notifyAll(); }
192
193 public boolean attempt(long msecs) throws InterruptedException {
194 if (Thread.interrupted()) throw new InterruptedException();
195 InterruptedException ie = null;
196 synchronized(this) {
197 if (msecs <= 0)
198 return startRead();
199 else if (startReadFromNewReader())
200 return true;
201 else {
202 long waitTime = msecs;
203 long start = System.currentTimeMillis();
204 for (;;) {
205 try { ReaderLock.this.wait(waitTime); }
206 catch(InterruptedException ex){
207 cancelledWaitingReader();
208 ie = ex;
209 break;
210 }
211 if (startReadFromWaitingReader())
212 return true;
213 else {
214 waitTime = msecs - (System.currentTimeMillis() - start);
215 if (waitTime <= 0) {
216 cancelledWaitingReader();
217 break;
218 }
219 }
220 }
221 }
222 }
223 // safeguard on interrupt or timeout:
224 writerLock_.signalWaiters();
225 if (ie != null) throw ie;
226 else return false; // timed out
227 }
228
229 }
230
231 protected class WriterLock extends Signaller implements Sync {
232
233 public void acquire() throws InterruptedException {
234 if (Thread.interrupted()) throw new InterruptedException();
235 InterruptedException ie = null;
236 synchronized(this) {
237 if (!startWriteFromNewWriter()) {
238 for (;;) {
239 try {
240 WriterLock.this.wait();
241 if (startWriteFromWaitingWriter())
242 return;
243 }
244 catch(InterruptedException ex){
245 cancelledWaitingWriter();
246 WriterLock.this.notify();
247 ie = ex;
248 break;
249 }
250 }
251 }
252 }
253 if (ie != null) {
254 // Fall through outside synch on interrupt.
255 // On exception, we may need to signal readers.
256 // It is not worth checking here whether it is strictly necessary.
257 readerLock_.signalWaiters();
258 throw ie;
259 }
260 }
261
262 public void release(){
263 Signaller s = endWrite();
264 if (s != null) s.signalWaiters();
265 }
266
267 synchronized void signalWaiters() { WriterLock.this.notify(); }
268
269 public boolean attempt(long msecs) throws InterruptedException {
270 if (Thread.interrupted()) throw new InterruptedException();
271 InterruptedException ie = null;
272 synchronized(this) {
273 if (msecs <= 0)
274 return startWrite();
275 else if (startWriteFromNewWriter())
276 return true;
277 else {
278 long waitTime = msecs;
279 long start = System.currentTimeMillis();
280 for (;;) {
281 try { WriterLock.this.wait(waitTime); }
282 catch(InterruptedException ex){
283 cancelledWaitingWriter();
284 WriterLock.this.notify();
285 ie = ex;
286 break;
287 }
288 if (startWriteFromWaitingWriter())
289 return true;
290 else {
291 waitTime = msecs - (System.currentTimeMillis() - start);
292 if (waitTime <= 0) {
293 cancelledWaitingWriter();
294 WriterLock.this.notify();
295 break;
296 }
297 }
298 }
299 }
300 }
301
302 readerLock_.signalWaiters();
303 if (ie != null) throw ie;
304 else return false; // timed out
305 }
306
307 }
308
309
310
311 }
312