Mercurial > hg > blitz_condensed
diff src/EDU/oswego/cs/dl/util/concurrent/SyncCollection.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EDU/oswego/cs/dl/util/concurrent/SyncCollection.java Sat Mar 21 11:00:06 2009 +0000 @@ -0,0 +1,509 @@ +/* + File: SyncCollection.java + + Originally written by Doug Lea and released into the public domain. + This may be used for any purposes whatsoever without acknowledgment. + Thanks for the assistance and support of Sun Microsystems Labs, + and everyone contributing, testing, and using this code. + + History: + Date Who What + 1Aug1998 dl Create public version +*/ + +package EDU.oswego.cs.dl.util.concurrent; +import java.util.*; + +/** + * SyncCollections wrap Sync-based control around java.util.Collections. + * They are similar in operation to those provided + * by java.util.Collection.synchronizedCollection, but have + * several extended capabilities. + * <p> + * The Collection interface is conceptually broken into two + * parts for purposes of synchronization control. The purely inspective + * reader operations are: + * <ul> + * <li> size + * <li> isEmpty + * <li> toArray + * <li> contains + * <li> containsAll + * <li> iterator + * </ul> + * The possibly mutative writer operations (which are also + * the set of operations that are allowed to throw + * UnsupportedOperationException) are: + * <ul> + * <li> add + * <li> addAll + * <li> remove + * <li> clear + * <li> removeAll + * <li> retainAll + * </ul> + * + * <p> + * SyncCollections can be used with either Syncs or ReadWriteLocks. + * When used with + * single Syncs, the same lock is used as both the reader and writer lock. + * The SyncCollection class cannot itself guarantee that using + * a pair of read/write locks will always correctly protect objects, since + * Collection implementations are not precluded from internally + * performing hidden unprotected state changes within conceptually read-only + * operations. However, they do work with current java.util implementations. + * (Hopefully, implementations that do not provide this natural + * guarantee will be clearly documentented as such.) + * <p> + * This class provides a straight implementation of Collections interface. + * In order to conform to this interface, sync failures + * due to interruption do NOT result in InterruptedExceptions. + * Instead, upon detection of interruption, + * <ul> + * <li> All mutative operations convert the interruption to + * an UnsupportedOperationException, while also propagating + * the interrupt status of the thread. Thus, unlike normal + * java.util.Collections, SyncCollections can <em>transiently</em> + * behave as if mutative operations are not supported. + * <li> All read-only operations + * attempt to return a result even upon interruption. In some contexts, + * such results will be meaningless due to interference, but + * provide best-effort status indications that can be useful during + * recovery. The cumulative number of synchronization failures encountered + * during such operations is accessible using method + * <code>synchronizationFailures()</code>. + * Non-zero values may indicate serious program errors. + * </ul> + * <p> + * The iterator() method returns a SyncCollectionIterator with + * properties and methods that are analogous to those of SyncCollection + * itself: hasNext and next are read-only, and remove is mutative. + * These methods allow fine-grained controlled access, but do <em>NOT</em> + * preclude concurrent modifications from being interleaved with traversals, + * which may lead to ConcurrentModificationExceptions. + * However, the class also supports method <code>unprotectedIterator</code> + * that can be used in conjunction with the <code>readerSync</code> or + * <code>writerSync</code> methods to perform locked traversals. For example, + * to protect a block of reads: + * <pre> + * Sync lock = coll.readerSync(); + * try { + * lock.acquire(); + * try { + * Iterator it = coll.unprotectedIterator(); + * while (it.hasNext()) + * System.out.println(it.next()); + * } + * finally { + * lock.release(); + * } + * } + * catch (InterruptedException ex) { ... } + * </pre> + * If you need to protect blocks of writes, you must use some + * form of <em>reentrant</em> lock (for example <code>ReentrantLock</code> + * or <code>ReentrantWriterPreferenceReadWriteLock</code>) as the Sync + * for the collection in order to allow mutative methods to proceed + * while the current thread holds the lock. For example, you might + * need to hold a write lock during an initialization sequence: + * <pre> + * Collection c = new SyncCollection(new ArrayList(), + * new ReentrantWriterPreferenceReadWriteLock()); + * // ... + * c.writeLock().acquire(); + * try { + * for (...) { + * Object x = someStream.readObject(); + * c.add(x); // would block if writeLock not reentrant + * } + * } + * catch (IOException iox) { + * ... + * } + * finally { + * c.writeLock().release(); + * } + * catch (InterruptedException ex) { ... } + * </pre> + * <p> + * (It would normally be better practice here to not make the + * collection accessible until initialization is complete.) + * <p> + * This class does not specifically support use of + * timed synchronization through the attempt method. However, + * you can obtain this effect via + * the TimeoutSync class. For example: + * <pre> + * Mutex lock = new Mutex(); + * TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts + * Collection c = new SyncCollection(new HashSet(), timedlock); + * </pre> + * <p> + * The same can be done with read-write locks: + * <pre> + * ReadWriteLock rwl = new WriterPreferenceReadWriteLock(); + * Sync rlock = new TimeoutSync(rwl.readLock(), 100); + * Sync wlock = new TimeoutSync(rwl.writeLock(), 100); + * Collection c = new SyncCollection(new HashSet(), rlock, wlock); + * </pre> + * <p> + * In addition to synchronization control, SyncCollections + * may be useful in any context requiring before/after methods + * surrounding collections. For example, you can use ObservableSync + * to arrange notifications on method calls to collections, as in: + * <pre> + * class X { + * Collection c; + * + * static class CollectionObserver implements ObservableSync.SyncObserver { + * public void onAcquire(Object arg) { + * Collection coll = (Collection) arg; + * System.out.println("Starting operation on" + coll); + * // Other plausible responses include performing integrity + * // checks on the collection, updating displays, etc + * } + * public void onRelease(Object arg) { + * Collection coll = (Collection) arg; + * System.out.println("Finished operation on" + coll); + * } + * } + * + * X() { + * ObservableSync s = new ObservableSync(); + * c = new SyncCollection(new HashSet(), s); + * s.setNotificationArgument(c); + * CollectionObserver obs = new CollectionObserver(); + * s.attach(obs); + * } + * ... + * } + * </pre> + * + * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] + * @see LayeredSync + * @see TimeoutSync +**/ + + +public class SyncCollection implements Collection { + protected final Collection c_; // Backing Collection + protected final Sync rd_; // sync for read-only methods + protected final Sync wr_; // sync for mutative methods + + protected final SynchronizedLong syncFailures_ = new SynchronizedLong(0); + + /** + * Create a new SyncCollection protecting the given collection, + * and using the given sync to control both reader and writer methods. + * Common, reasonable choices for the sync argument include + * Mutex, ReentrantLock, and Semaphores initialized to 1. + * <p> + * <b>Sample Usage</b> + * <pre> + * Collection c = new SyncCollection(new ArrayList(), new Mutex()); + * </pre> + **/ + public SyncCollection(Collection collection, Sync sync) { + this (collection, sync, sync); + } + + + /** + * Create a new SyncCollection protecting the given collection, + * and using the given ReadWriteLock to control reader and writer methods. + * <p> + * <b>Sample Usage</b> + * <pre> + * Collection c = new SyncCollection(new HashSet(), + * new WriterPreferenceReadWriteLock()); + * </pre> + **/ + public SyncCollection(Collection collection, ReadWriteLock rwl) { + this (collection, rwl.readLock(), rwl.writeLock()); + } + + /** + * Create a new SyncCollection protecting the given collection, + * and using the given pair of locks to control reader and writer methods. + **/ + public SyncCollection(Collection collection, Sync readLock, Sync writeLock) { + c_ = collection; + rd_ = readLock; + wr_ = writeLock; + } + + /** + * Return the Sync object managing read-only operations + **/ + + public Sync readerSync() { + return rd_; + } + + /** + * Return the Sync object managing mutative operations + **/ + + public Sync writerSync() { + return wr_; + } + + /** + * Return the number of synchronization failures for read-only operations + **/ + public long syncFailures() { + return syncFailures_.get(); + } + + + /** Try to acquire sync before a reader operation; record failure **/ + protected boolean beforeRead() { + try { + rd_.acquire(); + return false; + } + catch (InterruptedException ex) { + syncFailures_.increment(); + return true; + } + } + + /** Clean up after a reader operation **/ + protected void afterRead(boolean wasInterrupted) { + if (wasInterrupted) { + Thread.currentThread().interrupt(); + } + else + rd_.release(); + } + + + + public int size() { + boolean wasInterrupted = beforeRead(); + try { + return c_.size(); + } + finally { + afterRead(wasInterrupted); + } + } + + public boolean isEmpty() { + boolean wasInterrupted = beforeRead(); + try { + return c_.isEmpty(); + } + finally { + afterRead(wasInterrupted); + } + } + + public boolean contains(Object o) { + boolean wasInterrupted = beforeRead(); + try { + return c_.contains(o); + } + finally { + afterRead(wasInterrupted); + } + } + + public Object[] toArray() { + boolean wasInterrupted = beforeRead(); + try { + return c_.toArray(); + } + finally { + afterRead(wasInterrupted); + } + } + + public Object[] toArray(Object[] a) { + boolean wasInterrupted = beforeRead(); + try { + return c_.toArray(a); + } + finally { + afterRead(wasInterrupted); + } + } + + public boolean containsAll(Collection coll) { + boolean wasInterrupted = beforeRead(); + try { + return c_.containsAll(coll); + } + finally { + afterRead(wasInterrupted); + } + } + + + public boolean add(Object o) { + try { + wr_.acquire(); + try { + return c_.add(o); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + public boolean remove(Object o) { + try { + wr_.acquire(); + try { + return c_.remove(o); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + public boolean addAll(Collection coll) { + try { + wr_.acquire(); + try { + return c_.addAll(coll); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + public boolean removeAll(Collection coll) { + try { + wr_.acquire(); + try { + return c_.removeAll(coll); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + + public boolean retainAll(Collection coll) { + try { + wr_.acquire(); + try { + return c_.retainAll(coll); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + + public void clear() { + try { + wr_.acquire(); + try { + c_.clear(); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + + /** Return the base iterator of the underlying collection **/ + public Iterator unprotectedIterator() { + boolean wasInterrupted = beforeRead(); + try { + return c_.iterator(); + } + finally { + afterRead(wasInterrupted); + } + } + + public Iterator iterator() { + boolean wasInterrupted = beforeRead(); + try { + return new SyncCollectionIterator(c_.iterator()); + } + finally { + afterRead(wasInterrupted); + } + } + + public class SyncCollectionIterator implements Iterator { + protected final Iterator baseIterator_; + + SyncCollectionIterator(Iterator baseIterator) { + baseIterator_ = baseIterator; + } + + public boolean hasNext() { + boolean wasInterrupted = beforeRead(); + try { + return baseIterator_.hasNext(); + } + finally { + afterRead(wasInterrupted); + } + } + + public Object next() { + boolean wasInterrupted = beforeRead(); + try { + return baseIterator_.next(); + } + finally { + afterRead(wasInterrupted); + } + } + + public void remove() { + try { + wr_.acquire(); + try { + baseIterator_.remove(); + } + finally { + wr_.release(); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnsupportedOperationException(); + } + } + + } +} + +