1 33 34 package edu.rice.cs.util; 35 36 import java.util.LinkedList ; 37 38 82 public class ReaderWriterLock { 83 84 private volatile int _numActiveReaders = 0; 85 86 private volatile int _numActiveWriters = 0; 87 88 private volatile int _numWaitingReaders = 0; 89 90 private volatile int _numWaitingWriters = 0; 91 92 100 private final LinkedList <ReaderWriterThread> _waitQueue; 101 102 108 private final LinkedList <Thread > _runningThreads; 109 110 111 public ReaderWriterLock() { 112 _waitQueue = new LinkedList <ReaderWriterThread>(); 113 _runningThreads = new LinkedList <Thread >(); 114 } 115 116 121 public synchronized void startRead() { 122 if (!_alreadyReading()) { 124 125 _ensureNotAlreadyRunning(); 127 128 if (_numWaitingWriters > 0 || _numActiveWriters > 0) { 130 _numWaitingReaders++; 132 Reader r = new Reader(); 133 r.startWaiting(); 134 135 _numWaitingReaders--; 137 } 138 } 139 140 _numActiveReaders++; 142 _runningThreads.add(Thread.currentThread()); 143 } 144 145 150 public synchronized void endRead() { 151 if (_numActiveReaders == 0) { 152 throw new IllegalStateException ("Trying to end a read with no active readers!"); 153 } 154 155 _numActiveReaders--; 156 _ensureAlreadyRunning(); 157 _runningThreads.remove(Thread.currentThread()); 158 159 if (_numActiveWriters > 0) { 161 String msg = "A writer was active during a read!"; 162 throw new UnexpectedException(new Exception (msg)); 163 } 164 165 if (_numActiveReaders == 0) { 167 _wakeFrontGroupOfWaitQueue(); 170 } 171 } 172 173 174 180 public synchronized void startWrite() { 181 _ensureNotAlreadyRunning(); 183 184 if ((_numActiveReaders > 0 || _numActiveWriters > 0) || 191 (_numWaitingReaders > 0 || _numWaitingWriters > 0)) { 192 _numWaitingWriters++; 194 195 200 Writer w = new Writer(); 201 w.startWaiting(); 202 203 _numWaitingWriters--; 204 } 205 206 _numActiveWriters++; 208 _runningThreads.add(Thread.currentThread()); 209 } 210 211 217 public synchronized void endWrite() { 218 if (_numActiveWriters != 1) { 219 throw new IllegalStateException ("Trying to end a write with " + 220 _numActiveWriters + " active writers!"); 221 } 222 223 _numActiveWriters--; 224 _ensureAlreadyRunning(); 225 _runningThreads.remove(Thread.currentThread()); 226 227 if ((_numActiveWriters > 0) || (_numActiveReaders > 0)) { 229 String msg = "Multiple readers/writers were active during a write!"; 230 throw new UnexpectedException(new Exception (msg)); 231 } 232 233 _wakeFrontGroupOfWaitQueue(); 235 } 236 237 238 private boolean _alreadyReading() { 239 return _numActiveReaders > 0 && 242 _runningThreads.contains(Thread.currentThread()); 243 244 } 245 246 250 private void _ensureNotAlreadyRunning() { 251 if (_runningThreads.contains(Thread.currentThread())) { 252 throw new IllegalStateException ("Same thread cannot read or write multiple " + 253 "times! (Would cause deadlock.)"); 254 } 255 } 256 257 261 private void _ensureAlreadyRunning() { 262 if (!_runningThreads.contains(Thread.currentThread())) { 263 throw new IllegalStateException ("Current thread did not initiate a read or write!"); 264 } 265 } 266 267 268 private synchronized void _wakeFrontGroupOfWaitQueue() { 269 if (!_waitQueue.isEmpty()) { 270 ReaderWriterThread front = _waitQueue.getFirst(); 272 front.stopWaiting(); 274 if (front.isReader()) { 276 while (!_waitQueue.isEmpty()) { 277 front = _waitQueue.getFirst(); 278 if (front.isReader()) { 279 front.stopWaiting(); } 281 else { 282 break; 284 } 285 } 286 } 287 } 288 } 289 290 291 297 public abstract class ReaderWriterThread { 298 private volatile boolean _isWaiting = true; 299 300 public abstract boolean isWriter(); 301 302 public abstract boolean isReader(); 303 304 306 public void startWaiting() { 307 synchronized(ReaderWriterLock.this) { 308 _isWaiting = true; 309 _waitQueue.addLast(this); 310 while (_isWaiting) { 311 try { ReaderWriterLock.this.wait(); } 312 catch (InterruptedException e) { 313 } 315 } 316 } 317 } 318 319 320 public void stopWaiting() { 321 synchronized(ReaderWriterLock.this) { 322 _isWaiting = false; 323 _waitQueue.remove(this); ReaderWriterLock.this.notifyAll(); 325 } 326 } 327 } 328 329 330 public class Reader extends ReaderWriterThread { 331 public boolean isReader() { return true; } 332 public boolean isWriter() { return false; } 333 } 334 335 336 public class Writer extends ReaderWriterThread { 337 public boolean isReader() { return false; } 338 public boolean isWriter() { return true; } 339 } 340 } | Popular Tags |