KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > core > util > thread > WriterPreferenceReadWriteLock


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.core.util.thread;
19
20 /*
21    Originally written by Doug Lea and released into the public domain.
22    This may be used for any purposes whatsoever without acknowledgment.
23    Thanks for the assistance and support of Sun Microsystems Labs,
24    and everyone contributing, testing, and using this code.
25
26    History:
27    Date Who What
28    11 Jun1998 dl Create public version
29     5 Aug1998 dl replaced int counters with longs
30    25 aug1998 dl record writer thread
31     3 May1999 dl add notifications on interrupt/timeout
32  */

33
34
35 /**
36  * A ReadWriteLock that prefers waiting writers over
37  * waiting readers when there is contention. This class
38  * is adapted from the versions described in CPJ, improving
39  * on the ones there a bit by segregating reader and writer
40  * wait queues, which is typically more efficient.
41  * <p>
42  * The locks are <em>NOT</em> reentrant. In particular,
43  * even though it may appear to usually work OK,
44  * a thread holding a read lock should not attempt to
45  * re-acquire it. Doing so risks lockouts when there are
46  * also waiting writers.
47  * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
48  *
49  * @since carbon 2.0
50  * @author Doug Lea
51  * @version $Revision: 1.3 $($Author: dvoet $ / $Date: 2003/05/05 21:21:24 $)
52  **/

53 public class WriterPreferenceReadWriteLock implements ReadWriteLock {
54
55   protected long activeReaders_ = 0;
56   protected Thread JavaDoc activeWriter_ = null;
57   protected long waitingReaders_ = 0;
58   protected long waitingWriters_ = 0;
59
60
61   protected final ReaderLock readerLock_ = new ReaderLock();
62   protected final WriterLock writerLock_ = new WriterLock();
63
64   public Sync writeLock() { return writerLock_; }
65   public Sync readLock() { return readerLock_; }
66
67   /*
68     A bunch of small synchronized methods are needed
69     to allow communication from the Lock objects
70     back to this object, that serves as controller
71   */

72
73
74   protected synchronized void cancelledWaitingReader() { --waitingReaders_; }
75   protected synchronized void cancelledWaitingWriter() { --waitingWriters_; }
76
77
78   /** Override this method to change to reader preference **/
79   protected boolean allowReader() {
80     return activeWriter_ == null && waitingWriters_ == 0;
81   }
82
83
84   protected synchronized boolean startRead() {
85     boolean allowRead = allowReader();
86     if (allowRead) ++activeReaders_;
87     return allowRead;
88   }
89
90   protected synchronized boolean startWrite() {
91
92     // The allowWrite expression cannot be modified without
93
// also changing startWrite, so is hard-wired
94

95     boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);
96     if (allowWrite) activeWriter_ = Thread.currentThread();
97     return allowWrite;
98    }
99
100
101   /*
102      Each of these variants is needed to maintain atomicity
103      of wait counts during wait loops. They could be
104      made faster by manually inlining each other. We hope that
105      compilers do this for us though.
106   */

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

136   protected synchronized Signaller endRead() {
137     if (--activeReaders_ == 0 && waitingWriters_ > 0)
138       return writerLock_;
139     else
140       return null;
141   }
142
143
144   /**
145    * Called upon termination of a write.
146    * Returns the object to signal to wake up a waiter, or null if no such
147    **/

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

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