| ||||
|
Code - Class EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock1 /* 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 313 |
|||
Java API By Example, From Geeks To Geeks. |
Conditions of Use |
About Us
© 2002 - 2005, KickJava.com, or its affiliates
|