KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > concurrent > WriterPreferenceReadWriteLock


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 org.logicalcobwebs.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 JavaDoc 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() {
47         return writerLock_;
48     }
49
50     public Sync readLock() {
51         return readerLock_;
52     }
53
54     /*
55       A bunch of small synchronized methods are needed
56       to allow communication from the Lock objects
57       back to this object, that serves as controller
58     */

59
60
61     protected synchronized void cancelledWaitingReader() {
62         --waitingReaders_;
63     }
64
65     protected synchronized void cancelledWaitingWriter() {
66         --waitingWriters_;
67     }
68
69
70     /** Override this method to change to reader preference **/
71     protected boolean allowReader() {
72         return activeWriter_ == null && waitingWriters_ == 0;
73     }
74
75
76     protected synchronized boolean startRead() {
77         boolean allowRead = allowReader();
78         if (allowRead) ++activeReaders_;
79         return allowRead;
80     }
81
82     protected synchronized boolean startWrite() {
83
84         // The allowWrite expression cannot be modified without
85
// also changing startWrite, so is hard-wired
86

87         boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);
88         if (allowWrite) activeWriter_ = Thread.currentThread();
89         return allowWrite;
90     }
91
92
93     /*
94        Each of these variants is needed to maintain atomicity
95        of wait counts during wait loops. They could be
96        made faster by manually inlining each other. We hope that
97        compilers do this for us though.
98     */

99
100     protected synchronized boolean startReadFromNewReader() {
101         boolean pass = startRead();
102         if (!pass) ++waitingReaders_;
103         return pass;
104     }
105
106     protected synchronized boolean startWriteFromNewWriter() {
107         boolean pass = startWrite();
108         if (!pass) ++waitingWriters_;
109         return pass;
110     }
111
112     protected synchronized boolean startReadFromWaitingReader() {
113         boolean pass = startRead();
114         if (pass) --waitingReaders_;
115         return pass;
116     }
117
118     protected synchronized boolean startWriteFromWaitingWriter() {
119         boolean pass = startWrite();
120         if (pass) --waitingWriters_;
121         return pass;
122     }
123
124     /**
125      * Called upon termination of a read.
126      * Returns the object to signal to wake up a waiter, or null if no such
127      **/

128     protected synchronized Signaller endRead() {
129         if (--activeReaders_ == 0 && waitingWriters_ > 0)
130             return writerLock_;
131         else
132             return null;
133     }
134
135
136     /**
137      * Called upon termination of a write.
138      * Returns the object to signal to wake up a waiter, or null if no such
139      **/

140     protected synchronized Signaller endWrite() {
141         activeWriter_ = null;
142         if (waitingReaders_ > 0 && allowReader())
143             return readerLock_;
144         else if (waitingWriters_ > 0)
145             return writerLock_;
146         else
147             return null;
148     }
149
150
151     /**
152      * Reader and Writer requests are maintained in two different
153      * wait sets, by two different objects. These objects do not
154      * know whether the wait sets need notification since they
155      * don't know preference rules. So, each supports a
156      * method that can be selected by main controlling object
157      * to perform the notifications. This base class simplifies mechanics.
158      **/

159
160     protected abstract class Signaller { // base for ReaderLock and WriterLock
161
abstract void signalWaiters();
162     }
163
164     protected class ReaderLock extends Signaller implements Sync {
165
166         public void acquire() throws InterruptedException JavaDoc {
167             if (Thread.interrupted()) throw new InterruptedException JavaDoc();
168             InterruptedException JavaDoc ie = null;
169             synchronized (this) {
170                 if (!startReadFromNewReader()) {
171                     for (; ;) {
172                         try {
173                             ReaderLock.this.wait();
174                             if (startReadFromWaitingReader())
175                                 return;
176                         } catch (InterruptedException JavaDoc ex) {
177                             cancelledWaitingReader();
178                             ie = ex;
179                             break;
180                         }
181                     }
182                 }
183             }
184             if (ie != null) {
185                 // fall through outside synch on interrupt.
186
// This notification is not really needed here,
187
// but may be in plausible subclasses
188
writerLock_.signalWaiters();
189                 throw ie;
190             }
191         }
192
193
194         public void release() {
195             Signaller s = endRead();
196             if (s != null) s.signalWaiters();
197         }
198
199
200         synchronized void signalWaiters() {
201             ReaderLock.this.notifyAll();
202         }
203
204         public boolean attempt(long msecs) throws InterruptedException JavaDoc {
205             if (Thread.interrupted()) throw new InterruptedException JavaDoc();
206             InterruptedException JavaDoc ie = null;
207             synchronized (this) {
208                 if (msecs <= 0)
209                     return startRead();
210                 else if (startReadFromNewReader())
211                     return true;
212                 else {
213                     long waitTime = msecs;
214                     long start = System.currentTimeMillis();
215                     for (; ;) {
216                         try {
217                             ReaderLock.this.wait(waitTime);
218                         } catch (InterruptedException JavaDoc ex) {
219                             cancelledWaitingReader();
220                             ie = ex;
221                             break;
222                         }
223                         if (startReadFromWaitingReader())
224                             return true;
225                         else {
226                             waitTime = msecs - (System.currentTimeMillis() - start);
227                             if (waitTime <= 0) {
228                                 cancelledWaitingReader();
229                                 break;
230                             }
231                         }
232                     }
233                 }
234             }
235             // safeguard on interrupt or timeout:
236
writerLock_.signalWaiters();
237             if (ie != null)
238                 throw ie;
239             else
240                 return false; // timed out
241
}
242
243     }
244
245     protected class WriterLock extends Signaller implements Sync {
246
247         public void acquire() throws InterruptedException JavaDoc {
248             if (Thread.interrupted()) throw new InterruptedException JavaDoc();
249             InterruptedException JavaDoc ie = null;
250             synchronized (this) {
251                 if (!startWriteFromNewWriter()) {
252                     for (; ;) {
253                         try {
254                             WriterLock.this.wait();
255                             if (startWriteFromWaitingWriter())
256                                 return;
257                         } catch (InterruptedException JavaDoc ex) {
258                             cancelledWaitingWriter();
259                             WriterLock.this.notify();
260                             ie = ex;
261                             break;
262                         }
263                     }
264                 }
265             }
266             if (ie != null) {
267                 // Fall through outside synch on interrupt.
268
// On exception, we may need to signal readers.
269
// It is not worth checking here whether it is strictly necessary.
270
readerLock_.signalWaiters();
271                 throw ie;
272             }
273         }
274
275         public void release() {
276             Signaller s = endWrite();
277             if (s != null) s.signalWaiters();
278         }
279
280         synchronized void signalWaiters() {
281             WriterLock.this.notify();
282         }
283
284         public boolean attempt(long msecs) throws InterruptedException JavaDoc {
285             if (Thread.interrupted()) throw new InterruptedException JavaDoc();
286             InterruptedException JavaDoc ie = null;
287             synchronized (this) {
288                 if (msecs <= 0)
289                     return startWrite();
290                 else if (startWriteFromNewWriter())
291                     return true;
292                 else {
293                     long waitTime = msecs;
294                     long start = System.currentTimeMillis();
295                     for (; ;) {
296                         try {
297                             WriterLock.this.wait(waitTime);
298                         } catch (InterruptedException JavaDoc ex) {
299                             cancelledWaitingWriter();
300                             WriterLock.this.notify();
301                             ie = ex;
302                             break;
303                         }
304                         if (startWriteFromWaitingWriter())
305                             return true;
306                         else {
307                             waitTime = msecs - (System.currentTimeMillis() - start);
308                             if (waitTime <= 0) {
309                                 cancelledWaitingWriter();
310                                 WriterLock.this.notify();
311                                 break;
312                             }
313                         }
314                     }
315                 }
316             }
317
318             readerLock_.signalWaiters();
319             if (ie != null)
320                 throw ie;
321             else
322                 return false; // timed out
323
}
324
325     }
326
327
328 }
329
330
Popular Tags