| ||||
|
Code - Class EDU.oswego.cs.dl.util.concurrent.SyncCollection1 /* 2 File: SyncCollection.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 1Aug1998 dl Create public version 12 */ 13 14 package EDU.oswego.cs.dl.util.concurrent; 15 import java.util.*; 16 17 /** 18 * SyncCollections wrap Sync-based control around java.util.Collections. 19 * They are similar in operation to those provided 20 * by java.util.Collection.synchronizedCollection, but have 21 * several extended capabilities. 22 * <p> 23 * The Collection interface is conceptually broken into two 24 * parts for purposes of synchronization control. The purely inspective 25 * reader operations are: 26 * <ul> 27 * <li> size 28 * <li> isEmpty 29 * <li> toArray 30 * <li> contains 31 * <li> containsAll 32 * <li> iterator 33 * </ul> 34 * The possibly mutative writer operations (which are also 35 * the set of operations that are allowed to throw 36 * UnsupportedOperationException) are: 37 * <ul> 38 * <li> add 39 * <li> addAll 40 * <li> remove 41 * <li> clear 42 * <li> removeAll 43 * <li> retainAll 44 * </ul> 45 * 46 * <p> 47 * SyncCollections can be used with either Syncs or ReadWriteLocks. 48 * When used with 49 * single Syncs, the same lock is used as both the reader and writer lock. 50 * The SyncCollection class cannot itself guarantee that using 51 * a pair of read/write locks will always correctly protect objects, since 52 * Collection implementations are not precluded from internally 53 * performing hidden unprotected state changes within conceptually read-only 54 * operations. However, they do work with current java.util implementations. 55 * (Hopefully, implementations that do not provide this natural 56 * guarantee will be clearly documentented as such.) 57 * <p> 58 * This class provides a straight implementation of Collections interface. 59 * In order to conform to this interface, sync failures 60 * due to interruption do NOT result in InterruptedExceptions. 61 * Instead, upon detection of interruption, 62 * <ul> 63 * <li> All mutative operations convert the interruption to 64 * an UnsupportedOperationException, while also propagating 65 * the interrupt status of the thread. Thus, unlike normal 66 * java.util.Collections, SyncCollections can <em>transiently</em> 67 * behave as if mutative operations are not supported. 68 * <li> All read-only operations 69 * attempt to return a result even upon interruption. In some contexts, 70 * such results will be meaningless due to interference, but 71 * provide best-effort status indications that can be useful during 72 * recovery. The cumulative number of synchronization failures encountered 73 * during such operations is accessible using method 74 * <code>synchronizationFailures()</code>. 75 * Non-zero values may indicate serious program errors. 76 * </ul> 77 * <p> 78 * The iterator() method returns a SyncCollectionIterator with 79 * properties and methods that are analogous to those of SyncCollection 80 * itself: hasNext and next are read-only, and remove is mutative. 81 * These methods allow fine-grained controlled access, but do <em>NOT</em> 82 * preclude concurrent modifications from being interleaved with traversals, 83 * which may lead to ConcurrentModificationExceptions. 84 * However, the class also supports method <code>unprotectedIterator</code> 85 * that can be used in conjunction with the <code>readerSync</code> or 86 * <code>writerSync</code> methods to perform locked traversals. For example, 87 * to protect a block of reads: 88 * <pre> 89 * Sync lock = coll.readerSync(); 90 * try { 91 * lock.acquire(); 92 * try { 93 * Iterator it = coll.unprotectedIterator(); 94 * while (it.hasNext()) 95 * System.out.println(it.next()); 96 * } 97 * finally { 98 * lock.release(); 99 * } 100 * } 101 * catch (InterruptedException ex) { ... } 102 * </pre> 103 * If you need to protect blocks of writes, you must use some 104 * form of <em>reentrant</em> lock (for example <code>ReentrantLock</code> 105 * or <code>ReentrantWriterPreferenceReadWriteLock</code>) as the Sync 106 * for the collection in order to allow mutative methods to proceed 107 * while the current thread holds the lock. For example, you might 108 * need to hold a write lock during an initialization sequence: 109 * <pre> 110 * Collection c = new SyncCollection(new ArrayList(), 111 * new ReentrantWriterPreferenceReadWriteLock()); 112 * // ... 113 * c.writeLock().acquire(); 114 * try { 115 * for (...) { 116 * Object x = someStream.readObject(); 117 * c.add(x); // would block if writeLock not reentrant 118 * } 119 * } 120 * catch (IOException iox) { 121 * ... 122 * } 123 * finally { 124 * c.writeLock().release(); 125 * } 126 * catch (InterruptedException ex) { ... } 127 * </pre> 128 * <p> 129 * (It would normally be better practice here to not make the 130 * collection accessible until initialization is complete.) 131 * <p> 132 * This class does not specifically support use of 133 * timed synchronization through the attempt method. However, 134 * you can obtain this effect via 135 * the TimeoutSync class. For example: 136 * <pre> 137 * Mutex lock = new Mutex(); 138 * TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts 139 * Collection c = new SyncCollection(new HashSet(), timedlock); 140 * </pre> 141 * <p> 142 * The same can be done with read-write locks: 143 * <pre> 144 * ReadWriteLock rwl = new WriterPreferenceReadWriteLock(); 145 * Sync rlock = new TimeoutSync(rwl.readLock(), 100); 146 * Sync wlock = new TimeoutSync(rwl.writeLock(), 100); 147 * Collection c = new SyncCollection(new HashSet(), rlock, wlock); 148 * </pre> 149 * <p> 150 * In addition to synchronization control, SyncCollections 151 * may be useful in any context requiring before/after methods 152 * surrounding collections. For example, you can use ObservableSync 153 * to arrange notifications on method calls to collections, as in: 154 * <pre> 155 * class X { 156 * Collection c; 157 * 158 * static class CollectionObserver implements ObservableSync.SyncObserver { 159 * public void onAcquire(Object arg) { 160 * Collection coll = (Collection) arg; 161 * System.out.println("Starting operation on" + coll); 162 * // Other plausible responses include performing integrity 163 * // checks on the collection, updating displays, etc 164 * } 165 * public void onRelease(Object arg) { 166 * Collection coll = (Collection) arg; 167 * System.out.println("Finished operation on" + coll); 168 * } 169 * } 170 * 171 * X() { 172 * ObservableSync s = new ObservableSync(); 173 * c = new SyncCollection(new HashSet(), s); 174 * s.setNotificationArgument(c); 175 * CollectionObserver obs = new CollectionObserver(); 176 * s.attach(obs); 177 * } 178 * ... 179 * } 180 * </pre> 181 * 182 * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] 183 * @see LayeredSync 184 * @see TimeoutSync 185 **/ 186 187 188 public class SyncCollection implements Collection { 189 protected final Collection c_; // Backing Collection 190 protected final Sync rd_; // sync for read-only methods 191 protected final Sync wr_; // sync for mutative methods 192 193 protected final SynchronizedLong syncFailures_ = new SynchronizedLong(0); 194 195 /** 196 * Create a new SyncCollection protecting the given collection, 197 * and using the given sync to control both reader and writer methods. 198 * Common, reasonable choices for the sync argument include 199 * Mutex, ReentrantLock, and Semaphores initialized to 1. 200 * <p> 201 * <b>Sample Usage</b> 202 * <pre> 203 * Collection c = new SyncCollection(new ArrayList(), new Mutex()); 204 * </pre> 205 **/ 206 public SyncCollection(Collection collection, Sync sync) { 207 this (collection, sync, sync); 208 } 209 210 211 /** 212 * Create a new SyncCollection protecting the given collection, 213 * and using the given ReadWriteLock to control reader and writer methods. 214 * <p> 215 * <b>Sample Usage</b> 216 * <pre> 217 * Collection c = new SyncCollection(new HashSet(), 218 * new WriterPreferenceReadWriteLock()); 219 * </pre> 220 **/ 221 public SyncCollection(Collection collection, ReadWriteLock rwl) { 222 this (collection, rwl.readLock(), rwl.writeLock()); 223 } 224 225 /** 226 * Create a new SyncCollection protecting the given collection, 227 * and using the given pair of locks to control reader and writer methods. 228 **/ 229 public SyncCollection(Collection collection, Sync readLock, Sync writeLock) { 230 c_ = collection; 231 rd_ = readLock; 232 wr_ = writeLock; 233 } 234 235 /** 236 * Return the Sync object managing read-only operations 237 **/ 238 239 public Sync readerSync() { 240 return rd_; 241 } 242 243 /** 244 * Return the Sync object managing mutative operations 245 **/ 246 247 public Sync writerSync() { 248 return wr_; 249 } 250 251 /** 252 * Return the number of synchronization failures for read-only operations 253 **/ 254 public long syncFailures() { 255 return syncFailures_.get(); 256 } 257 258 259 /** Try to acquire sync before a reader operation; record failure **/ 260 protected boolean beforeRead() { 261 try { 262 rd_.acquire(); 263 return false; 264 } 265 catch (InterruptedException ex) { 266 syncFailures_.increment(); 267 return true; 268 } 269 } 270 271 /** Clean up after a reader operation **/ 272 protected void afterRead(boolean wasInterrupted) { 273 if (wasInterrupted) { 274 Thread.currentThread().interrupt(); 275 } 276 else 277 rd_.release(); 278 } 279 280 281 282 public int size() { 283 boolean wasInterrupted = beforeRead(); 284 try { 285 return c_.size(); 286 } 287 finally { 288 afterRead(wasInterrupted); 289 } 290 } 291 292 public boolean isEmpty() { 293 boolean wasInterrupted = beforeRead(); 294 try { 295 return c_.isEmpty(); 296 } 297 finally { 298 afterRead(wasInterrupted); 299 } 300 } 301 302 public boolean contains(Object o) { 303 boolean wasInterrupted = beforeRead(); 304 try { 305 return c_.contains(o); 306 } 307 finally { 308 afterRead(wasInterrupted); 309 } 310 } 311 312 public Object[] toArray() { 313 boolean wasInterrupted = beforeRead(); 314 try { 315 return c_.toArray(); 316 } 317 finally { 318 afterRead(wasInterrupted); 319 } 320 } 321 322 public Object[] toArray(Object[] a) { 323 boolean wasInterrupted = beforeRead(); 324 try { 325 return c_.toArray(a); 326 } 327 finally { 328 afterRead(wasInterrupted); 329 } 330 } 331 332 public boolean containsAll(Collection coll) { 333 boolean wasInterrupted = beforeRead(); 334 try { 335 return c_.containsAll(coll); 336 } 337 finally { 338 afterRead(wasInterrupted); 339 } 340 } 341 342 343 public boolean add(Object o) { 344 try { 345 wr_.acquire(); 346 try { 347 return c_.add(o); 348 } 349 finally { 350 wr_.release(); 351 } 352 } 353 catch (InterruptedException ex) { 354 Thread.currentThread().interrupt(); 355 throw new UnsupportedOperationException(); 356 } 357 } 358 359 public boolean remove(Object o) { 360 try { 361 wr_.acquire(); 362 try { 363 return c_.remove(o); 364 } 365 finally { 366 wr_.release(); 367 } 368 } 369 catch (InterruptedException ex) { 370 Thread.currentThread().interrupt(); 371 throw new UnsupportedOperationException(); 372 } 373 } 374 375 public boolean addAll(Collection coll) { 376 try { 377 wr_.acquire(); 378 try { 379 return c_.addAll(coll); 380 } 381 finally { 382 wr_.release(); 383 } 384 } 385 catch (InterruptedException ex) { 386 Thread.currentThread().interrupt(); 387 throw new UnsupportedOperationException(); 388 } 389 } 390 391 public boolean removeAll(Collection coll) { 392 try { 393 wr_.acquire(); 394 try { 395 return c_.removeAll(coll); 396 } 397 finally { 398 wr_.release(); 399 } 400 } 401 catch (InterruptedException ex) { 402 Thread.currentThread().interrupt(); 403 throw new UnsupportedOperationException(); 404 } 405 } 406 407 408 public boolean retainAll(Collection coll) { 409 try { 410 wr_.acquire(); 411 try { 412 return c_.retainAll(coll); 413 } 414 finally { 415 wr_.release(); 416 } 417 } 418 catch (InterruptedException ex) { 419 Thread.currentThread().interrupt(); 420 throw new UnsupportedOperationException(); 421 } 422 } 423 424 425 public void clear() { 426 try { 427 wr_.acquire(); 428 try { 429 c_.clear(); 430 } 431 finally { 432 wr_.release(); 433 } 434 } 435 catch (InterruptedException ex) { 436 Thread.currentThread().interrupt(); 437 throw new UnsupportedOperationException(); 438 } 439 } 440 441 442 /** Return the base iterator of the underlying collection **/ 443 public Iterator unprotectedIterator() { 444 boolean wasInterrupted = beforeRead(); 445 try { 446 return c_.iterator(); 447 } 448 finally { 449 afterRead(wasInterrupted); 450 } 451 } 452 453 public Iterator iterator() { 454 boolean wasInterrupted = beforeRead(); 455 try { 456 return new SyncCollectionIterator(c_.iterator()); 457 } 458 finally { 459 afterRead(wasInterrupted); 460 } 461 } 462 463 public class SyncCollectionIterator implements Iterator { 464 protected final Iterator baseIterator_; 465 466 SyncCollectionIterator(Iterator baseIterator) { 467 baseIterator_ = baseIterator; 468 } 469 470 public boolean hasNext() { 471 boolean wasInterrupted = beforeRead(); 472 try { 473 return baseIterator_.hasNext(); 474 } 475 finally { 476 afterRead(wasInterrupted); 477 } 478 } 479 480 public Object next() { 481 boolean wasInterrupted = beforeRead(); 482 try { 483 return baseIterator_.next(); 484 } 485 finally { 486 afterRead(wasInterrupted); 487 } 488 } 489 490 public void remove() { 491 try { 492 wr_.acquire(); 493 try { 494 baseIterator_.remove(); 495 } 496 finally { 497 wr_.release(); 498 } 499 } 500 catch (InterruptedException ex) { 501 Thread.currentThread().interrupt(); 502 throw new UnsupportedOperationException(); 503 } 504 } 505 506 } 507 } 508 509 510 |
|||
Java API By Example, From Geeks To Geeks. |
Conditions of Use |
About Us
© 2002 - 2005, KickJava.com, or its affiliates
|