1 30 31 package com.nightlabs.util; 32 33 import java.lang.InterruptedException ; 34 import java.lang.IllegalThreadStateException ; 35 import java.util.ArrayList ; 36 import java.util.HashMap ; 37 38 113 114 public class RWLock implements RWLockable 115 { 116 122 private int currentLocks = 0; 123 124 133 public int getCurrentLockStatus() 134 { 135 synchronized (mutex) { return currentLocks; } 136 } 137 138 142 private Thread currentWriteThread = null; 143 144 153 private HashMap currentReadThreads = new HashMap (); 154 155 160 private HashMap savedReadLocks = new HashMap (); 161 162 163 170 private static class ReadLockCount 171 { 172 public int readLockCount = 0; 173 } 174 175 181 private int waitingWriters = 0; 182 183 187 private int waitingReaders = 0; 188 189 192 private Object mutex = new Object (); 193 194 private RWLockMan rwLockMan; 195 196 private String rwLockName = null; 197 198 public RWLock() 199 { 200 rwLockMan = RWLockMan.getRWLockMan(); 201 } 202 203 210 public RWLock(String _rwLockName) 211 { 212 this(); 213 this.rwLockName = _rwLockName; 214 } 215 216 228 public RWLock(String _rwLockName, boolean appendMemAddr) 229 { 230 this(); 231 if (appendMemAddr) { 232 StringBuffer sb = new StringBuffer (_rwLockName.length()+10); 233 sb.append(_rwLockName); 234 sb.append('@'); 235 sb.append(Integer.toHexString(hashCode())); 236 this.rwLockName = sb.toString(); 237 } 238 else 239 this.rwLockName = _rwLockName; 240 } 241 242 248 public int getWaitingWriters() 249 { 250 synchronized (mutex) { return waitingWriters; } 251 } 252 253 259 public int getWaitingReaders() 260 { 261 synchronized (mutex) { return waitingReaders; } 262 } 263 264 270 public Runnable getCurrentWriteThread() 271 { 272 synchronized (mutex) { return currentWriteThread; } 273 } 274 275 276 287 public void acquireReadLock() 288 throws DeadLockException 289 { 290 ReadLockCount rlc = null; 291 292 synchronized(mutex) { 293 Thread currentThread = Thread.currentThread(); 294 295 waitingReaders++; 296 try { 297 298 if (currentWriteThread != currentThread) { 302 303 rlc = (ReadLockCount)currentReadThreads.get(currentThread); 310 if (rlc == null || rlc.readLockCount == 0) { 311 312 if ((currentLocks < 0) || (waitingWriters != 0)) { 313 rwLockMan.beginWaitForLock(this, RWLockMan.MODE_READ); try { 315 316 try { 317 while ((currentLocks < 0) || (waitingWriters != 0)) 318 mutex.wait(); 319 } catch (InterruptedException x) { 320 throw new IllegalThreadStateException ("Waiting interrupted. Can't continue work in this situation, because threads my collide!"); 321 } 322 323 } finally { 324 rwLockMan.endWaitForLock(this, RWLockMan.MODE_READ); 325 } 326 } 328 if (rlc == null) { 329 rlc = new ReadLockCount(); 330 currentReadThreads.put(currentThread, rlc); 331 } } 334 } 336 } finally { 337 waitingReaders--; 338 } 339 340 rwLockMan.acquireLock(this, RWLockMan.MODE_READ, 1); 341 342 ArrayList lockStack = (ArrayList )lockStacksByThread.get(currentThread); 344 if (lockStack == null) { 345 lockStack = new ArrayList (); 346 lockStacksByThread.put(currentThread, lockStack); 347 } 348 lockStack.add(new Boolean (false)); 350 if (currentLocks >= 0) { 352 currentLocks++; 353 rlc.readLockCount++; 354 } 355 else { 356 rlc = (ReadLockCount)savedReadLocks.get(currentThread); 357 if (rlc == null) { 358 rlc = new ReadLockCount(); 359 savedReadLocks.put(currentThread, rlc); 360 } 361 rlc.readLockCount++; 362 } 364 } } 366 367 378 public void acquireWriteLock() 379 throws DeadLockException 380 { 381 synchronized(mutex) { 382 Thread currentThread = Thread.currentThread(); 383 384 waitingWriters++; 385 try { 386 387 if (currentThread != currentWriteThread) { 388 389 boolean endWaitInRWLockMan = false; 393 if (currentLocks != 0) { 394 rwLockMan.beginWaitForLock(this, RWLockMan.MODE_WRITE); 395 endWaitInRWLockMan = true; 396 } 397 try { 399 ReadLockCount rlc = (ReadLockCount)currentReadThreads.get(currentThread); 401 if (rlc != null && rlc.readLockCount > 0) { 402 savedReadLocks.put(currentThread, rlc); 403 currentReadThreads.remove(currentThread); 404 currentLocks -= rlc.readLockCount; 405 if (currentLocks < 0) 406 throw new IllegalStateException (currentThread+": currentLocks < 0!!!"); 407 408 rwLockMan.releaseLock(this, RWLockMan.MODE_READ, rlc.readLockCount); 409 410 mutex.notifyAll(); 411 } 412 413 if (currentLocks != 0) { 414 try { 415 while (currentLocks != 0) 416 mutex.wait(); 417 } catch (InterruptedException x) { 418 throw new IllegalThreadStateException (currentThread+": Waiting interrupted. Can't continue work in this situation, because threads my collide!"); 419 } 420 } 422 } finally { 423 if (endWaitInRWLockMan) 424 rwLockMan.endWaitForLock(this, RWLockMan.MODE_WRITE); 425 } 426 427 currentWriteThread = currentThread; 428 } 430 } finally { 431 waitingWriters--; 432 } 433 434 rwLockMan.acquireLock(this, RWLockMan.MODE_WRITE, 1); 435 436 ArrayList lockStack = (ArrayList )lockStacksByThread.get(currentThread); 437 if (lockStack == null) { 438 lockStack = new ArrayList (); 439 lockStacksByThread.put(currentThread, lockStack); 440 } 441 lockStack.add(new Boolean (true)); 443 currentLocks--; 444 } } 446 447 456 private HashMap lockStacksByThread = new HashMap (); 457 458 459 482 public void releaseLock() 483 { 484 synchronized(mutex) { 485 Thread currentThread = Thread.currentThread(); 486 487 if (currentLocks == 0) 488 throw new IllegalStateException (currentThread+": currentLocks == 0: releaseLock called without previous acquire!"); 489 490 ArrayList lockStack = (ArrayList )lockStacksByThread.get(currentThread); 491 if (lockStack == null) 492 throw new IllegalStateException (currentThread+": No lock stack registered for current thread!"); 493 494 if (lockStack.isEmpty()) 495 throw new IllegalStateException (currentThread+": lock stack of current thread is empty!"); 496 497 Boolean releaseWriteLock = (Boolean )lockStack.remove(lockStack.size()-1); 498 499 if (releaseWriteLock.booleanValue()) { 501 if (currentLocks > 0) 502 throw new IllegalStateException (currentThread+": currentLocks > 0, but we are trying to release a write lock!"); 503 504 currentLocks++; 505 506 if (currentLocks == 0) { 507 currentWriteThread = null; 508 509 ReadLockCount rlc = (ReadLockCount)savedReadLocks.remove(currentThread); 511 if (rlc != null) { 512 if (rlc.readLockCount > 0) { 513 526 currentLocks += rlc.readLockCount; 533 currentReadThreads.put(currentThread, rlc); 534 535 rwLockMan.acquireLock(this, RWLockMan.MODE_READ, rlc.readLockCount); 536 } } 539 } 541 rwLockMan.releaseLock(this, RWLockMan.MODE_WRITE, 1); 542 543 } 544 else { 546 if (currentLocks < 0) { if (currentThread != currentWriteThread) 548 throw new IllegalStateException (currentThread+": Current thread is not current write thread! Why are we here?"); 549 550 551 ReadLockCount rlc = (ReadLockCount)savedReadLocks.get(currentThread); 552 553 if (rlc == null || rlc.readLockCount == 0) 554 throw new IllegalStateException (currentThread+": Current thread does not have a read lock set, but tries to release one!"); 555 556 rlc.readLockCount--; 557 } else { 559 ReadLockCount rlc = (ReadLockCount)currentReadThreads.get(currentThread); 560 if (rlc == null || rlc.readLockCount == 0) 561 throw new IllegalStateException (currentThread+": Current thread does not have a read lock set, but tries to release one!"); 562 563 currentLocks--; 564 rlc.readLockCount--; 565 } 567 rwLockMan.releaseLock(this, RWLockMan.MODE_READ, 1); 568 569 } 570 571 mutex.notifyAll(); 572 } } 574 575 582 public String toString() 583 { 584 synchronized(mutex) { 585 StringBuffer sb = new StringBuffer (); 586 sb.append(this.getClass().getName()); 587 588 if (rwLockName == null) { 589 sb.append('@'); 590 sb.append(Integer.toHexString(hashCode())); 591 sb.append('{'); 592 } 593 else { 594 sb.append("{name="); 595 sb.append(rwLockName); 596 sb.append(','); 597 } 598 sb.append("status="); 599 sb.append(currentLocks); 600 sb.append(",waitingReaders="); 601 sb.append(waitingReaders); 602 sb.append(",waitingWriters="); 603 sb.append(waitingWriters); 604 sb.append(",currentWriteThread="); 605 sb.append(currentWriteThread); 606 sb.append('}'); 607 return sb.toString(); 608 } } 610 611 } | Popular Tags |